2013-02-10 15 views
5

Il capitolo sulle funzioni parziali dal libro Learn You a Haskell For Great Good contiene il seguente codice:Qual è l'equivalente Python di queste funzioni di ordine superiore Haskell?

multThree :: (Num a) => a -> a -> a -> a 
multThree x y z = x * y * z 

ghci> let multTwoWithNine = multThree 9 
ghci> multTwoWithNine 2 3 
54 
ghci> let multWithEighteen = multTwoWithNine 2 
ghci> multWithEighteen 10 
180 

Attualmente sto giocando con la libreria functools in Python, e sono riusciti a replicare il comportamento di quelle funzioni che lo utilizzano.

from functools import partial 

def multThree(x,y,z): 
    return x * y * z 

>>> multTwoWithNine = partial(multThree,9) 
>>> multTwoWithNine(2,3) 
>>> multWithEighteen = partial(multTwoWithNine,2) 
>>> multWithEighteen(10) 
180 

Una cosa vorrei ora fare è vedere se riesco a riprodurre alcune delle più interessanti funzioni di ordine superiore dallo stesso capitolo del libro, come ad esempio:

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c] 
zipWith' _ [] _ = [] 
zipWith' _ _ [] = [] 
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys 

Tuttavia, ho' Non sono sicuro di come fare questo, o se partial() è addirittura utile qui. funzione built map

+1

Si dovrebbe modificare e correggere le funzioni, assicurandosi che siano tutte sintatticamente corretto. Il tuo primo, ad esempio, manca dei suoi argomenti. –

+2

Tecnicamente dovresti usare 'partial' in qualsiasi conversione, poiché tutte le funzioni di Haskell sono automaticamente curried, e' partial' emula le abilità che le funzioni di curried devono essere parzialmente applicate. Oppure puoi scrivere le versioni python come funzioni al curry, ma poi devi chiamarle come 'foo (a) (b) (c)'. – Wes

+2

Nota secondaria: si desidera "funzioni parzialmente applicate" e non "funzioni parziali". La mappa –

risposta

5

Python comporta come zipWith Haskell:

>>> def add(x,y): return x + y 
... 
>>> map(add,[1,2,3],[10,20,30]) 
[11, 22, 33] 
+1

è incorporata e non definita in una libreria? –

+0

yes, map e add sono funzioni incorporate in Python –

+1

Suppongo di sperare in una spiegazione sul motivo per cui è (deve essere?) Incorporato. –

0

Questo codice Python agisce simile alla funzione zipWith' hai dato:

def zip_with(f, l1, l2): 
    if len(l1) == 0 or len(l2) == 0: 
     return [] 
    else: 
     return [f(l1[0], l2[0])] + zip_with(f, l1[1:], l2[1:]) 

Questa funzione ha un paio di difetti, tuttavia, rispetto alla funzione Haskell. Il primo è che non sembra carino, perché Python non ha una sintassi per la corrispondenza dei pattern; dobbiamo usare len, [0] e [1:] invece. Il secondo è che la funzione Python non utilizza la valutazione lazy in alcun modo, quindi zip_with passerà sempre attraverso l'intero elenco, anche quando potrebbe andare via con l'arresto anticipato. Il terzo è che questa funzione si chiama una volta per ogni elemento della lista risultante, e Python ha un limite di ricorsione di circa (o esattamente?) 1,000, quindi questa funzione genererà un'eccezione se la lista di output è più lunga di circa 1.000 elementi .

Il secondo e il terzo problema potrebbero essere risolti utilizzando invece i generatori.

+0

Puoi anche usare '[f (l1.pop(), l2.pop())] + zip_with (f, l1, l2) 'e quindi non c'è bisogno di brutto' [0] 'o' [1:] ' – ThatWeirdo

0

Questo è un buon candidato per usare built-in zip funzione e la lista di comprensione:

>>> zip_with = lambda fn, la, lb: [fn(a, b) for (a, b) in zip(la, lb)] 

>>> add2 = lambda x,y: x+y 
>>> zip_with(add2, range(10), range(1,11)) 
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19] 
Problemi correlati