2014-08-31 26 views
6

Voglio scrivere una funzione Haskell che restituisce un elenco aggiunto a se stesso conteggio delle volte (come lst * count in Python).La versione pointfree non viene compilata, ma quella puntuale?

Il mio primo tentativo è:

self_append_n :: Int -> [a] -> [a] 
self_append_n = concat . replicate 

Il mio ragionamento è che replicate accetta un conteggio e un valore, e produce un elenco di valori. Quando il valore è di per sé una lista, non resta che concatenare le liste insieme. Tuttavia, questo dà un errore di sconcertante:

Couldn't match type `[a0]' with `[a] -> [a]' 
Expected type: [[a0]] -> [a] -> [a] 
    Actual type: [[a0]] -> [a0] 
In the first argument of `(.)', namely `concat' 
In the expression: concat . replicate 
In an equation for `self_append_n': 
    self_append_n = concat . replicate 

Poi ho scritto una versione pointful:

self_append_n a b = concat $ replicate a b 

e funziona!

Perché la versione point-free non riesce a compilare, ma l'aggiunta di punti lo rende funzionante?

risposta

11

Probabilmente aiuta a parenthesise esplicitamente le firme:

selfAppend :: Int -> ([a]   -> [a]) 
replicate :: Int -> ([a]->[[a]]) 
concat  ::   [[a]]  -> [a] 

Se si tenta di comporre concat . replicate, si finisce per dare concat il risultato parziale appied di replicate, vale a dire [a] -> [[a]]. Ciò non si unifica con [[a]].

Prima di passare il risultato, è necessario passare prima gli argomenti allo replicate. IMO modo migliore per farlo è "semi-pointfree":

selfAppend n = concat . replicate n 

alternative meno leggibile sarebbe

selfAppend' = curry $ concat . uncurry replicate 
selfAppend'' = (concat.) . replicate 

o con l'operatore famigerato

(.:) :: (c->d) -> (a->b->c) -> a->b->d 
(.:) = (.).(.) 
-- `≡ fmap fmap fmap`, also a popular implementation... 

si può semplicemente scrivere

selfAppend''' = concat .: replicate 
+4

Ho capito. La composizione ha esito negativo perché il tipo di reso effettivo di replica non è un elenco, ma una funzione (che a sua volta restituisce un elenco). –

+1

Sì. Sfortunatamente, la filosofia di Haskell _curry everything_ non è sempre un vantaggio (anche se molto spesso lo è). – leftaroundabout