An expression impatient in Frege but lazy in Haskell?

In Haskell, the following code prints "[1,2,3,4,5":

foo = take 10 $ show $ numbersFrom 1 where numbersFrom start = start : numbersFrom (start + 1) -- could use [1..] 

But in Frege, he throws an OutOfMemoryError with the following code:

 foo = take 10 $ unpacked $ show $ numbersFrom 1 where numbersFrom start = start : numbersFrom (start + 1) 

Here the only difference is the unpacked function, which is needed to convert from String to [Char] and FWIW, the unpacked function is impatient. Why can't the whole expression be lazy like in Haskell? Is it possible to achieve something like Haskell in Frege here?

+6
source share
5 answers

I did not use Frege, but it seems to me that if unpacked is strict, then its argument should not be an infinite list. Try unpacked $ take 10 instead of take 10 $ unpacked .

+6
source

I do not know Frege, but according to the definition of the String language, there is java.lang.String , so you cannot build infinitely long strings (the memory problem is probably not related to unpack .

Since you know that each element of numbersFrom 1 will be displayed for at least 1 character, you can redefine the size of the list to display, then unpack, then take the number of desired characters:

 foo = take 10 $ unpacked $ show $ take 10 $ numbersFrom 1 where numbersFrom start = start : numbersFrom (start + 1) 

Or more generally:

 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 

If your listing is expensive, you can start to consider the number of commas, spaces, etc. and reduce the argument to a second take , but you get the idea.

+7
source

This will not work due to the infinite line that show is (not) creating. You will need a helper function that converts the list to a Char list.

It would be nice to have a standard function for this.


Edit February 22, 2013

The show class now has a new method:

 {-- '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 

Now the Haskell code that led to OutOfMemoryError can be written as:

 (println . packed . take 10 . showChars ) [1..] 
+4
source

Adding to other answers,

Since show returns a java.lang.String , it is not possible to display infinite lists. So I thought I could write another version of the show to bring back [Char] . This is what I came up with and it works.

 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 

Now the code in the question becomes like Haskell, and it does not explode with 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
source

Short answer: Lines are strict in Frege, but lazy in Haskell.

Lists are lazy in both languages. But in Frege, strings are not lists.

+2
source

Source: https://habr.com/ru/post/922892/


All Articles