(Inspiré par ma réponse à cette question .)
Considérez ce code (il est censé trouver le plus grand élément inférieur ou égal à une entrée donnée):
data TreeMap v = Leaf | Node Integer v (TreeMap v) (TreeMap v) deriving (Show, Read, Eq, Ord)
closestLess :: Integer -> TreeMap v -> Maybe (Integer, v)
closestLess i = precise Nothing where
precise :: Maybe (Integer, v) -> TreeMap v -> Maybe (Integer, v)
precise closestSoFar Leaf = closestSoFar
precise closestSoFar (Node k v l r) = case i `compare` k of
LT -> precise closestSoFar l
EQ -> Just (k, v)
GT -> precise (Just (k, v)) r
Ce n'est pas très paresseux. Une fois le GT
cas entré, nous savons avec certitude que la valeur de retour finale sera Just
quelque chose plutôt que Nothing
, mais le Just
reste n'est pas disponible avant la fin. Je voudrais rendre ce paresseux afin que le Just
soit disponible dès que le GT
cas est entré. Mon cas de test pour cela est que je veux Data.Maybe.isJust $ closestLess 5 (Node 3 () Leaf undefined)
évaluer True
plutôt que d'enfoncer. Voici une façon dont je peux penser à faire ceci:
data TreeMap v = Leaf | Node Integer v (TreeMap v) (TreeMap v) deriving (Show, Read, Eq, Ord)
closestLess :: Integer -> TreeMap v -> Maybe (Integer, v)
closestLess _ Leaf = Nothing
closestLess i (Node k v l r) = case i `compare` k of
LT -> closestLess i l
EQ -> Just (k, v)
GT -> Just (precise (k, v) r)
where
precise :: (Integer, v) -> TreeMap v -> (Integer, v)
precise closestSoFar Leaf = closestSoFar
precise closestSoFar (Node k v l r) = case i `compare` k of
LT -> precise closestSoFar l
EQ -> (k, v)
GT -> precise (k, v) r
Cependant, je me répète maintenant: la logique de base est maintenant à la fois closestLess
dans et dans precise
. Comment puis-je écrire ceci pour qu'il soit paresseux mais sans me répéter?