Voilà comment j'écrire votre code:
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)
Je suis arrivé à ce code comme suit. La première chose que j'ai faite a été d'utiliser un motif plutôt que des gardes, car c'est plus clair ici.La prochaine chose que j'ai faite était d'éliminer le liftM2
s. Ils sont inutiles ici, parce qu'ils sont toujours appelés avec une liste de taille unique; dans ce cas, c'est la même chose que d'appeler le map
. Donc, liftM2 (*) ps [10]
est juste map (* 10) ps
, et de même pour les autres sites d'appel. Si vous voulez un remplaçant pour liftM2
, cependant, vous pouvez utiliser l » <$>
Control.Applicative
(qui est juste fmap
) et <*>
pour remplacer liftMn
pour tout n
: liftMn f a b c ... z
devient f <$> a <*> b <*> c <*> ... <*> z
. Que ce soit ou non est une question de goût; Je l'aime bien. Mais ici, nous pouvons l'éliminer entièrement.
L'endroit suivant où j'ai simplifié le code original est le do ...
. Vous ne prenez jamais réellement profiter du fait que vous êtes dans une do
-bloc, et que le code peut devenir
let ps = increasing (n - 1)
last = map (`mod` 10) ps
next = map (* 10) ps
in alternateEndings next last
De là, en arrivant à mon code écrit essentiellement impliqué fusionnant tous vos map
s ensemble. L'un des seuls appels restants qui n'était pas un map
était zipWith
. Mais parce que vous avez effectivement zipWith alts next last
, vous ne travaillez qu'avec 10*p
et p `mod` 10
en même temps, donc nous pouvons les calculer dans la même fonction. Cela conduit à
let ps = increasing (n - 1)
in concat $ map alts ps
where alts p = map (10*p +) [y `mod` 10..9]
C'est essentiellement mon code: concat $ map ...
devrait toujours être concatMap
(qui, soit dit en passant, est =<<
dans la liste monade), nous utilisons uniquement ps
une fois pour que nous puissions plier, et je préfère let
à where
.
1: Techniquement, cela ne fonctionne que pour Applicative
s, donc si vous arrive d'utiliser une monade qui n'a pas été fait l'un, <$>
est `liftM`
et <*>
est `ap`
. Toutes les monades peuvent être faites foncteurs applicatifs, cependant, et beaucoup d'entre eux ont été.
J'ai choisi cette réponse comme étant celle qui correspond le mieux à la question initiale. Cependant, comme d'autres réponses le soulignent ci-dessous, je posais vraiment la mauvaise question, et la solution peut être représentée plus simplement. – stusmith