在Haskell中,以下代码打印“[1,2,3,4,5”:
foo = take 10 $ show $ numbersFrom 1 where
numbersFrom start = start : numbersFrom (start + 1) -- could use [1..]
但是在Frege中,它使用以下代码抛出OutOfMemoryError
:
foo = take 10 $ unpacked $ show $ numbersFrom 1 where
numbersFrom start = start : numbersFrom (start + 1)
此处唯一的区别是从unpacked
转换为String
和FWIW所需的[Char]
函数,unpacked
函数非常渴望。为什么整个表达式不能像Haskell一样懒惰?是否有可能在弗雷格实现与Haskell类似的东西?
答案 0 :(得分:7)
我不知道Frege,但是根据语言定义String
是java.lang.String
所以你不能构建无限长的字符串(内存不足问题可能与{{无关) 1}}渴望)。
因为您知道unpack
的每个元素将显示为至少1个字符,那么您可以过度估计列表的大小以显示然后解压缩,然后获取所需字符的数量:
numbersFrom 1
或更一般地说:
foo = take 10 $ unpacked $ show $ take 10 $ numbersFrom 1 where
numbersFrom start = start : numbersFrom (start + 1)
如果您的枚举很昂贵,那么您可以开始考虑逗号,空格等的数量,并将参数减少到第二个n = 10 -- number of characters to show
m = 1 -- minimum (map (length . show) xs) for some type of xs
foo :: a -> [Char]
foo = take n . unpack . show . take ((n+m-1) `div` m) . someEnumeration
where
someEnumeration :: a -> [a]
someEnumeration = undefined
,但您明白了。
答案 1 :(得分:6)
我没有使用弗雷格,但在我看来,如果unpacked
是严格的,那么它的论证不应该是无限的列表。请尝试使用unpacked $ take 10
代替take 10 $ unpacked
。
答案 2 :(得分:4)
由于show
生成(无)无限字符串,因此无效。
您需要一些帮助函数将列表转换为Char
列表。
为此设置标准功能可能会很好。
2013年2月22日编辑
班级Show
现在有了一种新方法:
{--
'showChars' addresses the problem of 'show'ing infinite values.
Because 'show' has type 'String' and 'String' is atomic, this would
try to create a string with infinite length, and hence is doomed to fail.
The default definition is
> showChars = String.toList . show
This is ok for all finite values. But instances for recursive types
should implement it in a way that produces a lazy list of characters.
Here is an example for the list instance:
> showChars [] = ['[', ']']
> showChars xs = '[' : ( tail [ c | x <- xs, c <- ',' : showChars x ] ++ [']'] )
-}
showChars :: show -> [Char]
showChars = String.toList . show
导致OutOfMemoryError
的Haskell代码现在可以写成:
(println . packed . take 10 . showChars ) [1..]
答案 3 :(得分:4)
添加其他答案,
由于show
返回java.lang.String
,因此无法显示无限列表。所以我想我可以写一个不同版本的show来代替[Char]
。这就是我想出来的,它正在发挥作用。
frege> :paste
class AltShow a where
altshow :: a -> [Char]
instance AltShow AltShow a => [a] where
altshow [] = []
altshow xs = concat $ (['['] : intersperse [','] ys) ++ [[']']] where
ys = map altshow xs
instance AltShow Int where
altshow = unpacked <~ show
intersperse :: a -> [a] -> [a]
intersperse _ [] = []
intersperse _ (x:[]) = [x]
intersperse sep (x : y : []) =
x : sep : y : []
intersperse sep (x : y : rest) =
x : sep : y : sep : intersperse sep rest
:q
Interpreting...
frege> altshow [1, 10, 2, 234]
res3 = ['[', '1', ',', '1', '0', ',', '2', ',', '2', '3', '4', ']']
frege> :t res3
res5 :: [Char]
frege> packed res3
res6 = [1,10,2,234]
frege> :t res6
res7 :: String
现在,问题中的代码与Haskell类似,并且它没有爆发出OutOfMemoryError:
frege> :paste
foo = take 10 $ altshow $ numbersFrom 1 where
numbersFrom start = start : numbersFrom (start + 1)
:q
Interpreting...
frege> foo
res9 = ['[', '1', ',', '2', ',', '3', ',', '4', ',', '5']
frege> packed foo
res11 = [1,2,3,4,5
答案 4 :(得分:2)
简短的回答:弗雷格的字符串是严格的,但在哈斯克尔则是懒惰的。
列表在两种语言中都是懒惰的。但在弗雷格,弦乐不是名单。