表达在弗雷格的渴望,但在哈斯克尔懒惰?

时间:2012-08-15 01:00:03

标签: haskell frege

在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类似的东西?

5 个答案:

答案 0 :(得分:7)

我不知道Frege,但是根据语言定义Stringjava.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)

简短的回答:弗雷格的字符串是严格的,但在哈斯克尔则是懒惰的。

列表在两种语言中都是懒惰的。但在弗雷格,弦乐不是名单。