Является ли что-то в предложении "where" в Haskell только один раз?
Когда у меня есть следующий код:
func n = m ++ [1] ++ m ++ [0] ++ m
where m = func2 n
Сколько раз вызывает функцию func2? Только один раз, в разделе where? Или он просто вычисляется снова каждый раз, когда я использую m?
Ответы
Ответ 1
Может быть, это вообще не оценивается (радость лени) - но если это так, его нужно оценивать только один раз - если хотите, вы можете попробовать себя 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
(чтобы его распечатать), вы получаете вызов.
Ответ 2
Ответ 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
Затем оценка func 3
в графах ghci
called...
[3,1called...
,3,0called...
,3]
Ответ 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 раза. Однако при компиляции он только распечатывает called
один раз при использовании -O2
. (Протестировано с помощью 7.10.2.)