2014-11-19 25 views
6

stavo rivedendo un po 'di codice e sono imbattuto nel seguente gemma, che scommetto è un copia-incolla di pointfree uscita:Quali sono i passaggi per dedurre questo codice pointfree?

(ho pensato che il seguente sarebbe più appropriata rispetto alla solita foo/bar per questa particolare domanda : P)

import Control.Monad (liftM2) 

data Battleship = Battleship { x :: Int 
          , y :: Int 
          } deriving Show 

placeBattleship :: Int -> Int -> Battleship 
placeBattleship x' y' = Battleship { x = x', y = y' } 

coordinates :: Battleship -> (Int, Int) 
coordinates = liftM2 (,) x y 

qualcuno essere così gentile da spiegare i passi necessari per semplificare da:

(i) coordinates b = (x b, y b)

a:

(ii) coordinates = liftM2 (,) x y?

In particolare, sono un po 'confuso sull'uso di liftM2 poiché non ero nemmeno a conoscenza del fatto che una monade si nascondesse in sottofondo.

So che (i) può anche essere rappresentato come: coordinates s = (,) (x s) (y s) ma non sono sicuro di dove/come procedere.


P.S. Quello che segue è il motivo per cui ho il sospetto che sia da pointfree (uscita è da GHCI e :pl è alias a pointfree):

λ: :pl coordinates s = (x s, y s) 
coordinates = liftM2 (,) x y 

risposta

9

Questa sfrutta l'istanza Monad per (->) r, chiamato anche il "lettore Monade". Questa è la monade delle funzioni da un tipo specifico a a. (Date un'occhiata here per la motivazione sul perché esiste in primo luogo.)

Per vedere come funziona per le varie funzioni, sostituire m con (r -> in m a. Ad esempio, se dobbiamo solo fare liftM, otteniamo:

liftM :: (a -> b) -> (m a -> m b) 
liftM :: (a -> b) -> ((r -> a) -> (r -> b)) 
     :: (a -> b) -> (r -> a) -> (r -> b) -- simplify parentheses 

... che è solo la composizione di funzione. Neat.

Possiamo fare la stessa cosa per liftM2:

liftM2 :: (a -> b -> c) -> m a -> m b -> m c 
liftM2 :: (a -> b -> c) -> (r -> a) -> (r -> b) -> (r -> c) 

Così quello che vediamo è un modo di comporre due funzioni one-discussione con un funzione a due argomenti. È un modo per generalizzare la normale composizione delle funzioni a più di un argomento. L'idea è che creiamo una funzione che prende un singolo r passando attraverso entrambe le funzioni a un argomento, ottenendo due argomenti da passare alla funzione a due argomenti. Quindi, se abbiamo f :: (r -> a), g :: (r -> b) e h :: (a -> b -> c), produciamo:

\ r -> h (f r) (h r) 

Ora, come si applica al codice? (,) è la funzione a due argomenti e x e sono funzioni a un argomento del tipo Battleship -> Int (perché è così che funzionano gli accessori di campo). Con questo in mente:

liftM2 (,) x y = \ r -> (,) (x r) (y r) 
       = \ r -> (x r, y r) 

Una volta interiorizzato l'idea di composizione multipla funzione come questa, il codice pointfree come questo diventa un po 'più leggibile-non c'è bisogno di utilizzare lo strumento pointfree! In questo caso, penso che la versione senza puntini sia ancora migliore, ma quella senza punti non è terribile.

5

La monade liftM2 sta lavorando qui è la funzione Monade (->) a. Questo è equivalente alla monade Reader, come potresti aver visto prima.

Richiamo la definizione di liftM2:

liftM2 :: Monad m => (a -> b -> r) -> m a -> m b -> m r 
liftM2 f ma mb = do 
    a <- ma 
    b <- mb 
    return $ f a b 

Così ora se sostituiamo a (,) per f, x per ma e y per mb, otteniamo

liftM2 (,) x y = do 
    a <- x 
    b <- y 
    return $ (,) a b 

Dal x, y :: Battleship -> Int che è equivalente a ((->) Battleship) Int, quindi m ~ (->) Battleship. La monade funzione è definita come

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

Essenzialmente la funzione monade fa è permette di estrarre l'uscita da diverse funzioni fornite hanno tutti lo stesso ingresso. Un esempio più chiaro potrebbe essere qualcosa di simile

test = do 
    a <- (^2) 
    b <- (^3) 
    c <- (^4) 
    d <- show 
    return (a, b, c, d) 

> test 2 
(4, 8, 16, "2") 
1

Si potrebbe facilmente riscrivere

data Battleship = Battleship { x :: Int 
          , y :: Int 
          } deriving Show 

placeBattleship :: Int -> Int -> Battleship 
placeBattleship x y = Battleship x y 

coordinates :: Battleship -> (Int, Int) 
coordinates (Battleship x y) = (x, y) 

Non è punto-stile libero, ma abbastanza semplice

Problemi correlati