2012-08-15 6 views
6

a Haskell, i codice seguente stampa "[1,2,3,4,5":Espressione desiderosa a Frege ma pigra a Haskell?

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

Ma in Frege, getta OutOfMemoryError con il seguente codice:

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

Qui il l'unica differenza è la funzione unpacked necessaria per convertire da String a [Char] e FWIW, la funzione unpacked è impaziente. Perché l'intera espressione non può essere pigra come in Haskell? È possibile ottenere qualcosa di simile a Haskell in Frege qui?

risposta

6

Non ho usato Frege, ma mi sembra che se unpacked è rigido, quindi il suo argomento non dovrebbe essere una lista infinita. Prova unpacked $ take 10 anziché take 10 $ unpacked.

+3

Le stringhe in Frege non sono elenchi. Quindi 'take 10' non può essere applicato al risultato di' show'. Quindi 'unpacked' è usato per convertire prima da' String' a '[Char]' e quindi 'take 10' è applicato alla lista. –

+3

Quindi quali sono 'String's in Frege? Sembra che siano 'java.lang.String' (vedi la definizione di Frege Language). Non riuscirai mai a valutare 'unpack' perché non sarà mai in grado di costruire la stringa! –

7

non so Frege, ma secondo la definizione del linguaggio String è java.lang.String quindi non si può costruire corde infinitamente lunghe (il fuori problema di memoria, probabilmente non ha nulla a che fare con unpack essere ansioso).

Perché sai ogni elemento di numbersFrom 1 verrà mostrato come almeno 1 carattere quindi è possibile over-approssimare la dimensione della lista per mostrare poi disfare, poi prendere il numero di caratteri desiderati:

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

o più in generale:

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 

Se il conteggio è costoso allora si può iniziare a prendere in considerazione il numero di virgole, spazi, ecc e ridurre l'argomento al secondo take, ma si ottiene l'idea.

4

Questo non funzionerà a causa della stringa infinita che è (non) prodotta da show. Avresti bisogno di una funzione di supporto che converta una lista in una lista di Char.

Probabilmente sarebbe meglio avere una funzione standard per questo.


Modifica 22 febbraio 2013

Classe Show ha ora un nuovo metodo:

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

Il codice Haskell che ha portato alla OutOfMemoryError ora può essere scritta come:

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

Aggiunta ad altre risposte,

Poiché show restituisce un java.lang.String, non è possibile visualizzare elenchi infiniti. Quindi ho pensato di poter scrivere una versione diversa dello show per restituire uno [Char]. Questo è quello che ho trovato e sta funzionando.

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 

Ora il codice nella questione diventa simile a Haskell e non sta esplodendo con 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 
+1

Penso che potremmo aggiungere un'operazione di classe a 'Show' che lo fa in questo modo e la cui implementazione predefinita è' toList <~ show' – Ingo

+0

Sì, questo è un modo migliore. Grazie. –

2

Risposta breve: Le stringhe sono rigorosi in Frege, ma pigro in Haskell.

Gli elenchi sono pigri in entrambe le lingue. Ma in Frege, le stringhe non sono liste.