Почему этот оператор Haskell не оценивает лениво?

У меня есть следующая функция, определяемая:

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

Новый вопрос, затем, состоит в том почему?

8
задан perimosocordiae 8 July 2010 в 17:54
поделиться

3 ответа

В 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 }
17
ответ дан 5 December 2019 в 10:39
поделиться

Я пропустил один момент, который делает ответ ниже ложным.


Потому что 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.
-2
ответ дан 5 December 2019 в 10:39
поделиться
Prelude> let ex 1 x = 1
Prelude> let ex b x = b ** x

Здесь вы не определяете функцию с двумя вариантами. Вы определяете функцию с одним регистром, а затем определяете ее снова, отменяя предыдущее определение.

Чтобы определить одну функцию с двумя шаблонами, используйте let ex 1 x = 1; ex b x = b ** x , т.е. разделяйте регистры точкой с запятой.

1
ответ дан 5 December 2019 в 10:39
поделиться
Другие вопросы по тегам:

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