(Inspirado pela minha resposta a esta pergunta .)
Considere este código (ele deve encontrar o maior elemento que é menor ou igual a uma determinada entrada):
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
Isso não é muito preguiçoso. Depois que o GT
caso é inserido, sabemos com certeza que o valor final de retorno será Just
algo em vez de Nothing
, mas o Just
ainda não estará disponível até o final. Eu gostaria de tornar isso mais preguiçoso para que ele Just
fique disponível assim que o GT
caso for inserido. Meu caso de teste para isso é que eu quero Data.Maybe.isJust $ closestLess 5 (Node 3 () Leaf undefined)
avaliar em True
vez de chegar ao fundo. Aqui está uma maneira de pensar em fazer isso:
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
No entanto, agora estou me repetindo: a lógica principal está agora em ambos closestLess
e em precise
. Como posso escrever isso para que seja preguiçoso, mas sem me repetir?