(Inspirado por mi respuesta a esta pregunta ).
Considere este código (se supone que debe encontrar el elemento más grande que sea menor o igual que una entrada dada):
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
Esto no es muy vago. Una vez que GTse ingresa el caso, sabemos con certeza que el valor de retorno final será Justalgo más que Nothing, pero Justaún no estará disponible hasta el final. Me gustaría hacerlo más perezoso para que Justesté disponible tan pronto como GTse ingrese el caso. Mi caso de prueba para esto es que quiero Data.Maybe.isJust $ closestLess 5 (Node 3 () Leaf undefined)evaluar en Truelugar de tocar fondo. Aquí hay una forma en que puedo pensar en hacer esto:
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
Sin embargo, ahora me estoy repitiendo: la lógica central ahora está en ambos closestLessy en precise. ¿Cómo puedo escribir esto para que sea flojo pero sin repetirme?