Почему эти функции оцениваются по-разному

я экспериментировал с haskell, и, пытаясь улучшить читаемость моего кода, я внезапно изменил его поведение. Я думал, что эти два варианта будут эквивалентны.

Оригинал:

f :: Eq c => c -> c -> [[c]] -> [[c]]
f d c acc  
  | c == d    = [] : acc
  | otherwise = ([c] ++ (head acc)) : tail acc

split :: Eq a => a -> [a] -> [[a]]
split delim = foldr (f delim) [[]]

второй вопрос:

f' :: Eq c => c -> c -> [[c]] -> [[c]]
f' d c (currentWord:wordsSoFar)  
  | c == d    = [] : currentWord : wordsSoFar
  | otherwise = (c : currentWord) : wordsSoFar

split' :: Eq a => a -> [a] -> [[a]]
split' delim = foldr (f' delim) [[]]

вот результаты запуска двух:

*Main> take 1 (split 5 [1..])
[[1,2,3,4]]
*Main> take 1 (split' 5 [1..])
*** Exception: stack overflow

2 ответов


ваша первая версия должна только оценить acc когда вы называете head и tail на нем, поэтому никакой оценки не происходит, когда c == d.

вторая версия должна знать, является ли acc пустым или нет, прежде чем он делает что-либо еще, поскольку ни один из другого кода не должен выполняться, если шаблон не соответствует. Это значит, что acc должен быть оценен, даже если c == d. Это приводит к бесконечному циклу.

вы можете сделать вторую версию работы с помощью неопровержимая закономерность такая:

f' d c ~(currentWord:wordsSoFar) =

делая шаблон неопровержимым, вы говорите, что знаете, что шаблон будет соответствовать, поэтому проверка не требуется. Если acc были пусты, это приведет к ошибке, когда (и если) вы использовали currentWord и wordsSoFar вместо неисчерпывающей ошибки шаблона происходит сразу (и независимо от того,currentWord и wordsSoFar на самом деле используется).


Я думаю этой должно быть эквивалентно:

f d c acc | c == d = [] : acc
f d c (currentWord:wordsSoFar) = (c : currentWord) : wordsSoFar

обратите внимание, что если c == d затем мы не пытаемся определить, является ли acc пустой или нет. (Все версии вашего кода фактически завершатся неудачей, если c == d и acc == []; Я полагаю, этого никогда не происходит.)