我定义了以下功能:
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
那么,新问题是为什么?
答案 0 :(得分:17)
在GHCi中,每个let
语句都引入了ex
的 new 定义,而不是您期望的多个模式案例。所以它会挂起,因为当你之后输入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 }
答案 1 :(得分:1)
Prelude> let ex 1 x = 1
Prelude> let ex b x = b ** x
这里没有定义两个案例的函数。您可以使用一个案例定义一个函数,然后再次定义它,覆盖先前的定义。
使用let ex 1 x = 1; ex b x = b ** x
定义一个具有两个模式的函数,即用分号分隔案例。
答案 2 :(得分:-2)
我错过了一点懒惰,这使得答案低于假。
因为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.