6

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]FWIWunpackedです。関数は熱心です。Haskell のように式全体を遅延できないのはなぜですか? ここで Frege で Haskell に似たものを達成することは可能ですか?

4

5 に答える 5

7

私は Frege を知りませんが、言語の定義によると、無限に長い文字列を作成すること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

列挙が高価な場合は、コンマや空白などの数を考慮に入れ始めて、引数を 2 番目の に減らすことtakeができますが、アイデアは得られます。

于 2012-08-15T01:49:36.700 に答える
6

unpacked私は Frege を使ったことがありませんが、が正格であれば、その引数は無限リストであってはならないように思えます。unpacked $ take 10の代わりに試してくださいtake 10 $ unpacked

于 2012-08-15T01:23:32.090 に答える
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

につながった Haskell コードは、OutOfMemoryError次のように記述できるようになりました。

(println . packed . take 10 . showChars ) [1..]
于 2012-08-15T08:16:46.637 に答える
4

他の回答に加えて、

showを返すため、java.lang.String無限リストを表示することはできません。そのため、代わりに a を返す別のバージョンの 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
于 2012-08-16T00:11:16.973 に答える
2

簡単な答え: 文字列は Frege では正格ですが、Haskell では怠惰です。

リストは両方の言語で怠惰です。しかし Frege では、文字列はリストではありません。

于 2012-08-17T09:33:09.577 に答える