sho*_*sti 41 haskell linked-list ghc
我只是好奇Haskell中列表的一些确切的实现细节(GHC特定的答案很好) - 他们是天真的链接列表,还是他们有任何特殊的优化?进一步来说:
length和(!!)(例如)必须遍历列表?length两次,它是否必须迭代两次)?fib = 1:1:zipWith (+) fib (tail fib),是否会递归计算每个值,还是依赖于先前的计算值?)任何其他有趣的实施细节将不胜感激.提前致谢!
luq*_*qui 35
列表在Haskell中没有特殊的操作处理.它们的定义如下:
data List a = Nil | Cons a (List a)
Run Code Online (Sandbox Code Playgroud)
只是用一些特殊的符号:[a]for List a,[]for Nil和(:)for Cons.如果您定义了相同并重新定义了所有操作,您将获得完全相同的性能.
因此,Haskell列表是单链接的.由于懒惰,它们通常用作迭代器. sum [1..n]在恒定空间中运行,因为此列表的未使用前缀随着总和的进展而被垃圾收集,并且在需要之前不会生成尾部.
至于#4:Haskell中的所有值都被记忆,除了函数没有为它们的参数保留一个memo表.因此,当您按照自己的定义进行定义fib时,结果将被缓存,并且将在O(n)时间内访问第n个斐波纳契数.但是,如果您以这种明显相同的方式定义它:
-- Simulate infinite lists as functions from Integer
type List a = Int -> a
cons :: a -> List a -> List a
cons x xs n | n == 0 = x
| otherwise = xs (n-1)
tailF :: List a -> List a
tailF xs n = xs (n+1)
fib :: List Integer
fib = 1 `cons` (1 `cons` (\n -> fib n + tailF fib n))
Run Code Online (Sandbox Code Playgroud)
(花一点时间注意你的定义的相似性)
然后不共享结果,并且将在O(fib n)(指数)时间访问第n个斐波纳契数.您可以说服函数与memoization库共享,例如data-memocombinators.
dav*_*420 10
据我所知(我不知道这有多少是针对GHC的)
length并且(!!)DO必须遍历列表.
我不认为列表有任何特殊的优化,但有一种技术适用于所有数据类型.
如果你有类似的东西
foo xs = bar (length xs) ++ baz (length xs)
Run Code Online (Sandbox Code Playgroud)
然后length xs将计算两次.
但如果相反,你有
foo xs = bar len ++ baz len
where len = length xs
Run Code Online (Sandbox Code Playgroud)
那么它只会被计算一次.
是.
是的,一旦计算了命名值的一部分,它将被保留,直到名称超出范围.(该语言不需要这个,但这是我理解实现行为的方式.)
ken*_*ytm 10
如果是这样,他们的值是否以任何方式缓存(即,如果我调用两次长度,它是否必须迭代两次)?
GHC不执行完全的共同表达消除.例如:
{-# NOINLINE aaaaaaaaa #-}
aaaaaaaaa :: [a] -> Int
aaaaaaaaa x = length x + length x
{-# NOINLINE bbbbbbbbb #-}
bbbbbbbbb :: [a] -> Int
bbbbbbbbb x = l + l where l = length x
main = bbbbbbbbb [1..2000000] `seq` aaaaaaaaa [1..2000000] `seq` return ()
Run Code Online (Sandbox Code Playgroud)
给予-ddump-simpl:
Main.aaaaaaaaa [NEVER Nothing] :: forall a_adp.
[a_adp] -> GHC.Types.Int
GblId
[Arity 1
NoCafRefs
Str: DmdType Sm]
Main.aaaaaaaaa =
\ (@ a_ahc) (x_adq :: [a_ahc]) ->
case GHC.List.$wlen @ a_ahc x_adq 0 of ww_anf { __DEFAULT ->
case GHC.List.$wlen @ a_ahc x_adq 0 of ww1_Xnw { __DEFAULT ->
GHC.Types.I# (GHC.Prim.+# ww_anf ww1_Xnw)
}
}
Main.bbbbbbbbb [NEVER Nothing] :: forall a_ado.
[a_ado] -> GHC.Types.Int
GblId
[Arity 1
NoCafRefs
Str: DmdType Sm]
Main.bbbbbbbbb =
\ (@ a_adE) (x_adr :: [a_adE]) ->
case GHC.List.$wlen @ a_adE x_adr 0 of ww_anf { __DEFAULT ->
GHC.Types.I# (GHC.Prim.+# ww_anf ww_anf)
}
Run Code Online (Sandbox Code Playgroud)
请注意两次aaaaaaaaa通话GHC.List.$wlen.
(事实上,因为x需要保留aaaaaaaaa,所以比它慢2倍bbbbbbbbb.)
| 归档时间: |
|
| 查看次数: |
8169 次 |
| 最近记录: |