(Ispirato dalla mia risposta a questa domanda .)
Considera questo codice (si suppone che trovi l'elemento più grande che sia inferiore o uguale a un dato input):
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
Questo non è molto pigro. Una volta GT
inserito il caso, sappiamo per certo che il valore di ritorno finale sarà Just
qualcosa piuttosto che Nothing
, ma il resto Just
non è disponibile fino alla fine. Vorrei rendere questo pigrone in modo che Just
sia disponibile non appena GT
viene inserito il caso. Il mio caso di prova per questo è che voglio Data.Maybe.isJust $ closestLess 5 (Node 3 () Leaf undefined)
valutare True
piuttosto che toccare il fondo. Ecco un modo in cui posso pensare di fare questo:
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
Tuttavia, ora mi sto ripetendo: la logica di base è ora in entrambi closestLess
e in precise
. Come posso scrivere questo in modo che sia pigro ma senza ripetermi?