Haskell 中的 'where' 子句中的某些内容只计算一次吗?
Is something in the 'where' clause in Haskell only calculated once?
当我有以下代码时:
func n = m ++ [1] ++ m ++ [0] ++ m
where m = func2 n
func2函数调用了多少次?只有一次,在 where 子句中?还是每次用m都重新计算?
也许它根本就没有被求值(偷懒的乐趣)——但如果是,它应该只被求值一次——如果你愿意,你可以自己尝试 trace
:
import Debug.Trace(trace)
func n = m ++ [1] ++ m ++ [0] ++ m
where m = func2 n
func2 n = trace "called..." [n]
这是 GHCi 中的示例:
λ> func 3
called...
[3,1,3,0,3]
这里是您看到它可能不会被调用的地方(直到您最终需要对其求值):
λ> let v = func 4
λ> v
called...
[4,1,4,0,4]
请参阅:起初它不会被调用 - 只有当您最终评估 v
(打印它)时,您才会收到调用。
Carsten 的答案(该值最多计算一次)是正确的,只要您没有禁用单态限制。如果你有,那么 m
可能有一个涉及类型 class 的多态推断类型,然后 m
并不是一个真正的正常值,而是一个接受类型 [=] 的函数19=] 字典并产生一个值。考虑这个例子。
{-# LANGUAGE NoMonomorphismRestriction #-}
import Debug.Trace(trace)
func n = m ++ [1] ++ m ++ [0] ++ m
where m = func2 n -- m :: Monad t => t a (where n :: a)
func2 n = trace "called..." (return n) -- func2 :: Monad t => a -> t a
然后在 ghci 打印中评估 func 3
called...
[3,1called...
,3,0called...
,3]
要添加到@Carstan 和@Reid Barton 的答案中,它还取决于您是否是 运行 编译代码,例如:
{-# LANGUAGE NoMonomorphismRestriction #-}
import Debug.Trace(trace)
func n = m ++ [1] ++ m ++ [0] ++ m
where m = func2 n -- m :: Monad t => t a (where n :: a)
func2 n = trace "called..." (return n)
main = let xs = func 3 :: [Int]
in print xs
在ghci
运行main
打印出called
3次。然而,在编译时,它只在使用 -O2
时打印出 called
一次。 (使用 7.10.2 测试。)
当我有以下代码时:
func n = m ++ [1] ++ m ++ [0] ++ m
where m = func2 n
func2函数调用了多少次?只有一次,在 where 子句中?还是每次用m都重新计算?
也许它根本就没有被求值(偷懒的乐趣)——但如果是,它应该只被求值一次——如果你愿意,你可以自己尝试 trace
:
import Debug.Trace(trace)
func n = m ++ [1] ++ m ++ [0] ++ m
where m = func2 n
func2 n = trace "called..." [n]
这是 GHCi 中的示例:
λ> func 3
called...
[3,1,3,0,3]
这里是您看到它可能不会被调用的地方(直到您最终需要对其求值):
λ> let v = func 4
λ> v
called...
[4,1,4,0,4]
请参阅:起初它不会被调用 - 只有当您最终评估 v
(打印它)时,您才会收到调用。
Carsten 的答案(该值最多计算一次)是正确的,只要您没有禁用单态限制。如果你有,那么 m
可能有一个涉及类型 class 的多态推断类型,然后 m
并不是一个真正的正常值,而是一个接受类型 [=] 的函数19=] 字典并产生一个值。考虑这个例子。
{-# LANGUAGE NoMonomorphismRestriction #-}
import Debug.Trace(trace)
func n = m ++ [1] ++ m ++ [0] ++ m
where m = func2 n -- m :: Monad t => t a (where n :: a)
func2 n = trace "called..." (return n) -- func2 :: Monad t => a -> t a
然后在 ghci 打印中评估 func 3
called...
[3,1called...
,3,0called...
,3]
要添加到@Carstan 和@Reid Barton 的答案中,它还取决于您是否是 运行 编译代码,例如:
{-# LANGUAGE NoMonomorphismRestriction #-}
import Debug.Trace(trace)
func n = m ++ [1] ++ m ++ [0] ++ m
where m = func2 n -- m :: Monad t => t a (where n :: a)
func2 n = trace "called..." (return n)
main = let xs = func 3 :: [Int]
in print xs
在ghci
运行main
打印出called
3次。然而,在编译时,它只在使用 -O2
时打印出 called
一次。 (使用 7.10.2 测试。)