(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 GTwpisaniu sprawy wiemy na pewno, że końcowa wartość zwrotna będzie Justczymś, a nie Nothing, ale Justnadal nie będzie dostępna do końca. Chciałbym uczynić to bardziej leniwym, aby Justbyło dostępne od razu po wpisaniu GTsprawy. Mój przypadek testowy polega na tym, że chcę Data.Maybe.isJust $ closestLess 5 (Node 3 () Leaf undefined)ocenić Trueraczej 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 closestLessi wewnątrz precise. Jak mogę to napisać, żeby było leniwe, ale nie powtarzałem się?