【问题标题】:Expression eager in Frege but lazy in Haskell?在 Frege 中表达渴望但在 Haskell 中很懒惰?
【发布时间】:2012-08-15 01:00:02
【问题描述】:

在 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 转换为[Char] 和FWIW 所必需的,unpacked 函数是急切的。为什么整个表达式不能像 Haskell 中那样懒惰?是否有可能在 Frege 中实现类似于 Haskell 的东西?

【问题讨论】:

    标签: haskell frege


    【解决方案1】:

    我不认识弗雷格,但根据语言定义 Stringjava.lang.String 所以你不能构建无限长的字符串(内存不足问题可能与 unpack 渴望无关) .

    因为您知道numbersFrom 1 的每个元素将显示为至少 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
    

    如果您的枚举很昂贵,那么您可以开始考虑逗号、空格等的数量,并将参数减少到第二个 take,但您明白了。

    【讨论】:

      【解决方案2】:

      我没有使用过 Frege,但在我看来,如果 unpacked 是严格的,那么它的参数不应该是无限列表。试试unpacked $ take 10 而不是take 10 $ unpacked

      【讨论】:

      • 弗雷格中的字符串不是列表。所以take 10 不能应用于show 的结果。因此unpacked 用于首先将String 转换为[Char],然后将take 10 应用于列表。
      • 那么弗雷格的Strings 是什么?看来他们是java.lang.String(参见弗雷格语言定义)。您将永远无法评估unpack,因为它永远无法构建字符串!
      【解决方案3】:

      添加到其他答案,

      由于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
      

      【讨论】:

      • 我认为我们可以向Show 添加一个类操作,它的默认实现是toList &lt;~ show
      • 是的,这是一个更好的方法。谢谢。
      【解决方案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..]
      

      【讨论】:

        【解决方案5】:

        简短回答:字符串在 Frege 中是严格的,但在 Haskell 中是惰性的。

        列表 在两种语言中都是惰性的。但是在弗雷格中,字符串不是列表。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-02-02
          • 1970-01-01
          • 1970-01-01
          • 2010-11-17
          • 1970-01-01
          • 2012-01-30
          • 2015-09-06
          • 2015-09-06
          相关资源
          最近更新 更多