(Вдохновлен моим ответом на этот вопрос .)
Рассмотрим этот код (он должен найти самый большой элемент, который меньше или равен заданному входу):
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
Это не очень лениво. После того, как GT
дело введено, мы точно знаем, что окончательное возвращаемое значение будет Just
чем-то Nothing
, а Just
не до конца. Я хотел бы сделать это более ленивым, чтобы Just
он был доступен, как только GT
дело введено. Мой тестовый пример для этого, что я хочу Data.Maybe.isJust $ closestLess 5 (Node 3 () Leaf undefined)
оценить, True
а не дно. Вот один из способов сделать это:
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
Однако сейчас я повторяюсь: основная логика теперь closestLess
и в, и в precise
. Как я могу написать это так, чтобы это было лениво, но не повторялось?