Domanda

Di tanto in tanto inciampo sul problema che voglio esprimere "si prega di utilizzare l'ultimo argomento due volte", per esempio al fine di scrivere stile pointfree o per evitare un lambda. Per es.

sqr x = x * x

potrebbe essere scritto come

sqr = doubleArgs (*) where
   doubleArgs f x = f x x

O considerare questa funzione un po 'più complicato (tratto da questa domanda ):

ins x xs = zipWith (\ a b -> a ++ (x:b)) (inits xs) (tails xs)

Potrei scrivere questo codice pointfree se ci fosse una funzione come questa:

ins x = dup (zipWith (\ a b -> a ++ (x:b))) inits tails where
     dup f f1 f2 x = f (f1 x) (f2 x)

Ma come non riesco a trovare qualcosa di simile doubleArgs o dup in Hoogle, quindi credo che potrei mancare un trucco o idioma qui.

È stato utile?

Soluzione

Da Control.Monad:

join :: (Monad m) -> m (m a) -> m a
join m = m >>= id

instance Monad ((->) r) where
    return = const
    m >>= f = \x -> f (m x) x

Espansione:

join :: (a -> a -> b) -> (a -> b)
join f = f >>= id
       = \x -> id (f x) x
       = \x -> f x x

Quindi, sì, Control.Monad.join.

Oh, e per il vostro esempio pointfree, Hai provato a usare la notazione applicativa (da Control.Applicative):

ins x = zipWith (\a b -> a ++ (x:b)) <$> inits <*> tails

(anche io non so perché la gente è così appassionato di a ++ (x:b) invece di a ++ [x] ++ b ... non più veloce è - l'inliner si prenderà cura di esso - e la seconda è molto più simmetrica Oh bene!)

Altri suggerimenti

Quello che tu chiami 'doubleArgs' è più spesso chiamato DUP - è il combinatore W (chiamato usignolo in Per Mock a Mockingbird) - "il duplicatore elementare".

Quello che tu chiami 'DUP' è in realtà il combinatore 'Starling-prime'.

Haskell ha un abbastanza piccolo "base combinatore" vedere Data.Function, più alcune operazioni applicative e monadiche aggiungere più combinatori "standard" in virtù delle istanze di funzione per applicativa e Monade (<*> dal applicativo è la S - storno combinatore per l'istanza funzionale, liftA2 & liftM2 sono Starling-prime). Non sembra essere molto entusiasmo nella comunità per l'espansione Data.Function, così mentre combinatori sono divertente, pragmaticamente sono venuto a preferire a lungo mano in situazioni in cui un combinatore non è direttamente disponibile.

Ecco un'altra soluzione per la seconda parte della mia domanda: Frecce

import Control.Arrow

ins x = inits &&& tails >>> second (map (x:)) >>> uncurry (zipWith (++))

Il &&& ( "fan-out") distribuisce un argomento per due funzioni e restituisce la coppia di risultati. >>> ( "e poi") inverte l'ordine di applicazione funzione, che permette di avere una catena di operazioni da sinistra a destra. second funziona solo sulla seconda parte di una coppia. Naturalmente è necessario un uncurry alla fine di alimentare la coppia in una funzione che si aspetta due argomenti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top