(Zainspirowany moją odpowiedzią na to pytanie ).
Rozważ ten kod (powinien znaleźć największy element, który jest mniejszy lub równy podanemu wejściu):
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
To nie jest zbyt leniwe. Po GT
wpisaniu sprawy wiemy na pewno, że końcowa wartość zwrotna będzie Just
czymś, a nie Nothing
, ale Just
nadal nie będzie dostępna do końca. Chciałbym uczynić to bardziej leniwym, aby Just
było dostępne od razu po wpisaniu GT
sprawy. Mój przypadek testowy polega na tym, że chcę Data.Maybe.isJust $ closestLess 5 (Node 3 () Leaf undefined)
ocenić True
raczej niż dno. Oto jeden ze sposobów, w jaki mogę to zrobić:
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
Jednak teraz powtarzam: podstawowa logika jest teraz zarówno w, jak closestLess
i wewnątrz precise
. Jak mogę to napisać, żeby było leniwe, ale nie powtarzałem się?