Haskell中'where'子句中的某些内容只计算一次吗?

Tho*_*mas 17 haskell where

当我有以下代码时:

func n = m ++ [1] ++ m ++ [0] ++ m
    where m = func2 n
Run Code Online (Sandbox Code Playgroud)

func2函数调用了多少次?只有一次,在where子句中?或者每次使用m时它是否只是再次计算?

Car*_*ten 19

也许它根本没有评估(懒惰的喜悦) - 但如果是,它应该只被评估一次 - 如果你愿意,你可以尝试自己trace:

import Debug.Trace(trace)

func n = m ++ [1] ++ m ++ [0] ++ m
  where m = func2 n

func2 n = trace "called..." [n]
Run Code Online (Sandbox Code Playgroud)

这是GHCi中的一个例子:

?> func 3
called...
[3,1,3,0,3]
Run Code Online (Sandbox Code Playgroud)

在这里你可以看到它可能不被调用(直到你最终需要评估它):

?> let v = func 4

?> v
called...
[4,1,4,0,4]
Run Code Online (Sandbox Code Playgroud)

请参阅:首先它没有被调用 - 只有当你最终评估v(打印它)时才能接到电话.


Rei*_*ton 8

只要您没有禁用单态限制,Carsten的答案(该值最多只能计算一次)是正确的.如果你有,那么m可能有一个涉及类型类的多态推断类型,然后m它不是一个普通的值,而是一个接受类型类字典并产生一个值的函数.考虑这个例子.

{-# 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
Run Code Online (Sandbox Code Playgroud)

然后func 3在ghci打印中进行评估

called...
[3,1called...
,3,0called...
,3]
Run Code Online (Sandbox Code Playgroud)