У меня есть следующая функция, определяемая:
ex 1 x = 1
ex 0 x = 0
ex b x = b ** x
Затем когда я выполняю следующее:
1 `ex` (sum [1..])
это пытается вычислить сумму бесконечной последовательности, вместо того, чтобы быть ленивым и возвратиться 1. Почему?
Править: После дальнейшего расследования я нашел, что лень происходит, если я определяю ex
функция в файле, но не, если я определяю его в GHCI:
$ ghci
GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help
Loading package base ... linking ... done.
Prelude> let ex 1 x = 1
Prelude> let ex b x = b ** x
Prelude> ex 1 (sum [1..])
<interactive>: out of memory (requested 1048576 bytes)
Если я вытягиваю ex
определение в файл (в этом случае, test.hs):
$ ghci
GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help
Loading package base ... linking ... done.
Prelude> :load test.hs
[1 of 1] Compiling Main ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main> ex 1 (sum [1..])
1.0
Новый вопрос, затем, состоит в том почему?
В GHCi, каждый Оператор let
вводит новое определение ex
вместо нескольких вариантов шаблонов, как вы ожидали. Таким образом, он зависает, потому что, когда вы вводите ex 1 (sum [1 ..])
впоследствии, существует только окончательная ex b x = b ** x
версия.
Если вы хотите определить функцию с несколькими вариантами шаблонов в GHCi, вам нужно поместить ее в один оператор let
, например:
let ex 1 x = 1; ex 0 x = 0; ex b x = b ** x
То же самое относится ко всему остальному, что может обычно записывается в несколько строк, например, в нотации do
. Например, такую функцию:
f x = do
y <- get
put (x + y)
return y
нужно было бы записать в GHCi так:
let f x = do { y <- get; put (x + y); return y }
Я пропустил один момент, который делает ответ ниже ложным.
Потому что sum
вычисляет общую сумму всех элементов в последовательности. Которая, в вашем случае, бесконечна.
Вы, вероятно, хотите
map ((curry ex) 1) [1..]
То есть
map -- map each item x to y
(
(
curry ex -- curry ex, to transform (x, y) -> z into x -> y -> z
)
1 -- then invoke it with 1, which results in y -> z, x being 1
)
[1..] -- the infinite sequence to be mapped.
Prelude> let ex 1 x = 1
Prelude> let ex b x = b ** x
Здесь вы не определяете функцию с двумя вариантами. Вы определяете функцию с одним регистром, а затем определяете ее снова, отменяя предыдущее определение.
Чтобы определить одну функцию с двумя шаблонами, используйте let ex 1 x = 1; ex b x = b ** x
, т.е. разделяйте регистры точкой с запятой.