Ecco come mi piacerebbe scrivere il vostro codice:
increasing :: Integer -> [Integer]
increasing 1 = [1..9]
increasing n = let allEndings x = map (10*x +) [x `mod` 10 .. 9]
in concatMap allEndings $ increasing (n - 1)
sono arrivato in questo codice come segue. La prima cosa che ho fatto è stata utilizzare la corrispondenza del modello invece delle guardie, poiché qui è più chiaro.La prossima cosa che ho fatto è stata eliminare il liftM2
s. Non sono necessari qui, perché vengono sempre chiamati con una lista di una dimensione; in tal caso, equivale a chiamare map
. Quindi liftM2 (*) ps [10]
è solo map (* 10) ps
e, analogamente, per gli altri siti di chiamata. Se si desidera una sostituzione generale per liftM2
, però, è possibile utilizzare Control.Applicative
s' <$>
(che è solo fmap
) e <*>
per sostituire liftMn
per qualsiasi n
: liftMn f a b c ... z
diventa f <$> a <*> b <*> c <*> ... <*> z
. Che sia più bello o meno è una questione di gusti; Mi piace piacermi. Ma qui, possiamo eliminarlo completamente.
Il prossimo luogo che ho semplificato il codice originale è do ...
. Non si può mai realmente sfruttare il fatto che si trovi in una do
-block, e in modo che il codice possa diventare
let ps = increasing (n - 1)
last = map (`mod` 10) ps
next = map (* 10) ps
in alternateEndings next last
Da qui, arrivando al mio codice di scrittura essenzialmente coinvolto fondendo tutto il vostro map
s insieme. Una delle uniche chiamate rimanenti che non era uno map
era zipWith
. Ma poiché hai effettivamente zipWith alts next last
, lavori solo con 10*p
e p `mod` 10
allo stesso tempo, così possiamo calcolarli nella stessa funzione. Questo porta a
let ps = increasing (n - 1)
in concat $ map alts ps
where alts p = map (10*p +) [y `mod` 10..9]
E questo è fondamentalmente il mio codice: concat $ map ...
deve sempre diventare concatMap
(che, per inciso, è =<<
nella lista Monade), usiamo solo ps
una volta in modo che possiamo piegarlo in, e preferisco let
a where
.
1: Tecnicamente, questo funziona solo per Applicative
s, quindi se vi capita di essere utilizzando una monade che non è stato fatto uno, <$>
è `liftM`
e <*>
è `ap`
. Comunque tutte le monadi possono essere fatte funtori applicativi, e molti di loro lo sono stati.
Ho scelto questa come risposta accettata in quanto segue da vicino la domanda originale. Tuttavia, come indicato da altre risposte, stavo davvero ponendo la domanda sbagliata e la soluzione può essere rappresentata più semplicemente. – stusmith