Combinazione di frammenti di codice Haskell per ottenere un quadro più ampio


12

Questo è il codice che ho trovato da qualche parte, ma voglio sapere come funziona:

    findIndices :: (a -> Bool) -> [a] -> [Int]
    findIndices _ [] = []
    findIndices pred xs = map fst (filter (pred . snd) (zip [0..] xs))

Output: findIndices (== 0) [1,2,0,3,0]==[2,4] , dove predè (==0)& xsè[1,2,0,3,0]

Mostrerò un po 'della mia comprensione:

    (zip [0..] xs)

Quello che fa la riga sopra è mettere gli indici in tutto l'elenco. Per l'ingresso di cui sopra, sarebbe simile a questa: [(0,1),(1,2),(2,0),(3,3),(4,0)].

    (pred . snd)

Ho scoperto che questo significa qualcosa di simile pred (snd (x)). La mia domanda è: xl'elenco è fatto dalla zipriga? Mi sto inclinando verso sì ma la mia ipotesi è fragile.

Successivamente, è la mia comprensione di fste snd. lo so

    fst(1,2) = 1 

e

    snd(1,2) = 2

Come hanno senso questi due comandi nel codice?

La mia comprensione filterè che restituisce un elenco di elementi che corrispondono a una condizione. Per esempio,

    listBiggerThen5 = filter (>5) [1,2,3,4,5,6,7,8,9,10]

darebbe [6,7,8,9,10]

La mia comprensione della mappa è che applica una funzione a tutti gli elementi dell'elenco. Per esempio,

    times4 :: Int -> Int
    times4 x = x * 4
    listTimes4 = map times4 [1,2,3,4,5]

darebbe [4,8,12,16,20]

Come funziona nel complesso? Penso di essere stato completo in quello che so finora, ma non riesco a mettere insieme i pezzi. Qualcuno può darmi una mano?


7
Vorrei solo dire che leggere questa domanda è stato un piacere raro. Otteniamo "come diavolo funziona questo codice?" domande frequenti, ma raramente con questo livello di spiegazione di ciò che il richiedente fa e non capisce già. Ciò rende davvero divertente scrivere una buona risposta mirata esattamente sui vuoti che hai.
Daniel Wagner,

Grazie Daniel! Ho trascorso molto tempo in questo problema ed è per questo che ho potuto individuare con cosa avevo bisogno di aiuto.
Shreeman Gautam,

Vorrei aggiungere che funziona anche la risposta @WillNess. È molto più facile da vedere e da capire.
Shreeman Gautam

Risposte:


2

In Haskell ci piace dire, segui i tipi . In effetti i pezzi si collegano come da fili che vanno dal tipo al tipo corrispondente:

(in primo luogo, la composizione della funzione è:

   (f >>> g) x  =  (g . f) x  =        g (f x)
   (f >>> g)    =  (g . f)    =  \x -> g (f x)

e la regola di inferenza del tipo di composizione della funzione è:

    f        :: a -> b                   --      x  :: a
          g  ::      b -> c              --    f x  :: b
   -------------------------             -- g (f x) :: c
    f >>> g  :: a ->      c
    g  .  f  :: a ->      c

Adesso, )

findIndices :: (b -> Bool) -> [b] -> [Int]
findIndices pred  = \xs -> map fst ( filter (pred . snd) ( zip [0..] xs ))
                  =        map fst . filter (pred . snd) . zip [0..]
                  =  zip [0..]  >>>  filter (snd >>> pred)  >>>  map fst
---------------------------------------------------------------------------
zip :: [a] ->          [b]        ->        [(a,  b)]
zip  [0..] ::          [b]        ->        [(Int,b)]
---------------------------------------------------------------------------
        snd           :: (a,b) -> b
                pred  ::          b -> Bool
       ------------------------------------
       (snd >>> pred) :: (a,b)      -> Bool
---------------------------------------------------------------------------
filter ::               (t          -> Bool) -> [t]   -> [t]
filter (snd >>> pred) ::                      [(a,b)] -> [(a,b)]
filter (snd >>> pred) ::                    [(Int,b)] -> [(Int,b)]
---------------------------------------------------------------------------
    fst ::                                   (a,   b) -> a
map     ::                                  (t        -> s) -> [t] -> [s]
map fst ::                                                 [(a,b)] -> [a]
map fst ::                                               [(Int,b)] -> [Int]

quindi, nel complesso,

zip  [0..] ::          [b]        ->        [(Int,b)]
filter (snd >>> pred) ::                    [(Int,b)] -> [(Int,b)]
map fst ::                                               [(Int,b)] -> [Int]
---------------------------------------------------------------------------
findIndices pred ::    [b] ->                                         [Int]

Hai chiesto, come si adattano questi pezzi?

Questo è come.


Con la comprensione dell'elenco , la tua funzione è scritta come

findIndices pred xs = [ i | (i,x) <- zip [0..] xs, pred x ]

che in pseudocodice recita:

msgstr "l 'elenco dei risultati contiene iper ognuno (i,x)in modo zip [0..] xstale che pred xcontiene" .

Lo fa ruotando il nlungo

xs = [a,b,...,z] = [a] ++ [b] ++ ... ++ [z]

in

  [0 | pred a] ++ [1 | pred b] ++ ... ++ [n-1 | pred z]

dove [a | True]è [a]ed [a | False]è [].


8

Ho scoperto che questo significa qualcosa di simile pred (snd (x)). La mia domanda è: x è la lista fatta dalla zip line? Mi sto inclinando verso sì ma la mia ipotesi è fragile.

Bene pred . snd, significa \x -> pred (snd x). Quindi questo costruisce fondamentalmente una funzione che mappa un elemento xsu pred (snd x).

Ciò significa quindi che l'espressione è simile a:

filter (\x -> pred (snd x)) (zip [0..] xs)

Ecco xquindi una 2 tupla generata da zip. Quindi per sapere se (0, 1),(1,2) , (2, 0), ecc vengono mantenute nel risultato, snd xprenderà il secondo elemento di questi 2-tuple (così 1, 2, 0, etc.), e controllare se il predtha elemento è soddisfatta o meno. Se è soddisfatto, manterrà l'elemento, altrimenti quell'elemento (la 2-tupla) verrà filtrato.

Quindi, se (== 0)è l' predice, allora filter (pred . snd) (zip [0..] xs)conterrà le 2 tuple [(2, 0), (4, 0)].

Ma ora il risultato è un elenco di 2 tuple. Se vogliamo gli indici, dobbiamo in qualche modo liberarci della 2-tupla e del secondo elemento di queste 2 tuple. Usiamo fst :: (a, b) -> aper questo: questo mappa una 2 tupla sul suo primo elemento. Quindi, per un elenco [(2, 0), (4, 0)], map fst [(2, 0), (4, 0)]tornerà [2, 4].


1
Ehi Willem, che bella spiegazione! Ora ho capito il codice completo. Grazie Signore!
Shreeman Gautam,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.