Haskell: Запись текстовых файлов и парсинг их назад к исходному формату

Я могу ответить на две трети вашего вопроса здесь - почему возникает конфликт, и как выяснить, что происходит. Я не знаю интерфейса PyCharm, поэтому могу только догадываться, что он вам показывает.

Почему конфликт

В скриншоте, который вы показываете, причина конфликта заключается в том, что у вас есть коммит, который добавляет блок, смежный с блоком, который еще не существует потому что вы решили перебазировать его позже в последовательности: я думаю, что вы добавляете test...spatial() после test...end(), но последнее еще не существует. Я предполагаю, что это будет добавлено, когда коммит, который добавляет это, будет рассмотрен позже.

Когда Git видит непрерывные изменения, он не продвигается вперед, потому что для этого нужно угадывать, а это не всегда безопасно. Вы должны рассмотреть их и разрешить конфликт, чтобы сказать, каков правильный результат.

Как узнать, что происходит

Я воспроизвел ваш сценарий, добавив «line1» в конце файла a в коммите, а затем добавив «line2» в второй коммит:

$ git log --format=oneline master
0a3b254 (master) line2
ef7e059 line1

Теперь я перезагружаюсь, чтобы отменить эти два коммита и получаю конфликт, когда выбираю 0a3b254 до ef7e059, а команда командной строки сообщает мне, какой коммит имеет конфликт и останавливается там:

$ git rebase -i HEAD^^
Auto-merging a
CONFLICT (content): Merge conflict in a
error: could not apply 0a3b254... line2

Теперь вы используете другой интерфейс, поэтому я не знаю, показывает ли он фиксацию проблемы, но git status сделает это, если вы запустите его в командной строке :

$ git status
interactive rebase in progress; onto bf27dcb
Last command done (1 command done):
   pick 0a3b254 line2
Next command to do (1 remaining command):
   pick ef7e059 line1

Теперь я могу проверить коммит, который я пытаюсь перебазировать с помощью git show 0a3b254, и он показывает, что я добавляю «line2» после «line1».

Я также могу посмотреть на a, чтобы увидеть, что это за конфликт:

$ cat a
asdf
<<<<<<< HEAD
=======
line1
line2
>>>>>>> 0a3b254... line2

Это говорит мне о том, что в master здесь не было строк (между <<<<<<< HEAD и ======= ) и что в 0a3b254 у меня есть две строки. Я знаю, какие из них оставить, выполнив git show 0a3b254, потому что в a на данный момент ничего не говорится о том, что оставить.

Поэтому я разрешаю конфликт, оставив только «line2» из моей версии, и продолжаю ребазинг:

# edit a to keep just line2
git add a
git rebase --continue
...
CONFLICT (content): Merge conflict in a
error: could not apply ef7e059... line1

Опять я снова получаю конфликт с ef7e059, потому что два блока были добавлены в то же самое место, и Git, конечно, не будет знать, в каком порядке их размещать.

$ cat a
asdf
<<<<<<< HEAD
line2
=======
line1
>>>>>>> ef7e059... line1

Здесь Git сообщает мне, что я добавил line2 в предыдущем коммите на HEAD и line1 в коммите, над которым я сейчас работаю, ef7e059. Это не помогает выяснить правильный порядок, также как и git show ef7e059, но git show mybranch:a показывает мне содержимое a в исходной ветви (так как ветвь не обновляется, пока перебазирование не завершено) и помогает мне понять что мне нужно вставить строку 2 после строки 1.

# edit a to place its contents in the right order
git add a
git rebase --continue

Предположение о графическом интерфейсе PyCharm

В вашем интерфейсе я ожидаю, что Результат (центральная панель) - это место, где вы должны поместить результат разрешения конфликта, левая панель, вероятно, является состоянием кода в коммите, выбранном вишней, а правая панель, вероятно, является состоянием кода, в котором происходит выбор вишни.

На основании комментариев к этому ответу и информации о добавлении, которую вы показали в вопросе, я бы предположил, что Result содержит неправильную функцию, которую вам, возможно, придется заменить на ту, которую этот коммит фактически пытается добавить.

Нет ничего плохого в том, чтобы пытаться: вы всегда можете попробовать и посмотреть, работает ли он, и позже отменить перебазирование, если окончательные результаты не идентичны (согласно git diff) коду перед перебазированием.

8
задан Bill the Lizard 18 September 2012 в 14:02
поделиться

3 ответа

Определено в Prelude ,

type ShowS = String -> String
class Show a where
    showsPrec :: Int -> a -> ShowS
    show :: a -> String
    showList :: [a] -> ShowS

type ReadS a = String -> [(a, String)]
class Read a where
    readsPrec :: Int -> ReadS a
    readList :: ReadS [a]
read :: (Read a) => String -> a

Короче это стандартные методы сериализации в Haskell. show :: (Show a) => a -> String может превратить все, что является экземпляром Show в строку, а read :: (Read a) = > String -> a может превратить строку во все, что является экземпляром Read (или сгенерировать исключение).

Большинство встроенных типов и структур данных в стандартной библиотеке иметь Показывать и Читать экземпляров; если вы составляете части из них, ваш тип также имеет экземпляры Show и Read .

type Table = [(String, String)]

load :: (Read a) => FilePath -> IO a
load f = do s <- readFile f
            return (read s)

save :: (Show a) => a -> FilePath -> IO ()
save x f = writeFile f (show x)

Если Table был типом данных,

12
ответ дан 5 December 2019 в 08:25
поделиться

The show/read approach will work fine, I use it as well, but only for small values. On larger, more complex values read will be very slow.

This contrived example demonstrates the bad performance of read:

data RevList a = (RevList a) :< a | Nil
  deriving (Show, Read)

ghci> read "(((((((((((((((Nil)))))))))))))))" :: RevList Int

Also, read won't be able to read some valid Haskell expressions, especially ones that use infix constructors (like the :< in my example). The reason for this is that read is unaware of the fixity of operators. This is also why show $ Nil :< 1 :< 2 :< 3 will generate a lot of seemingly redundant parentheses.

If you want to have serialization for bigger values, I'd suggest to use some other library like Data.Binary. This will be somewhat more complex than a simple show, mainly because of the lack of deriving Binary. However, there are various generic programming solutions to give you deriving-like surrogates.

Conclusion: I'd say, use the show/read solution until you reach its limits (probably once you start building actual applications), then start looking at something more scalable (but also more complex) like Data.Binary.


Side note: To those interested in parsers and more advanced Haskell stuff; The examples I gave came from the paper: Haskel Do You Read Me?, on an alternative, fast read-like function.

5
ответ дан 5 December 2019 в 08:25
поделиться

С вашей текущей функцией у вас есть проблема, когда строки в списке содержат «,» или «)», потому что это делает невозможным узнать, где заканчивается строка, когда вы пытаетесь прочитать данные снова. Вам нужно каким-то образом экранировать эти символы всякий раз, когда они появляются в строке.

Гораздо проще использовать show и read для преобразования ваших данных в строки и обратно в сделайте это самостоятельно:

save :: Table -> IO ()
save zs = writeFile "database.txt" (show zs)

show экранирует специальные символы и проверяет, что данные имеют формат, который может быть проанализирован с помощью read . Чтобы загрузить данные, вы должны прочитать файл в строку и передать его в , прочитать , чтобы преобразовать его в желаемую структуру данных.

3
ответ дан 5 December 2019 в 08:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: