(Натхненний моєю відповіддю на це запитання .)
Розглянемо цей код (він повинен знайти найбільший елемент, менший або рівний даному входу):
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
. Як я можу написати це, щоб це ліниво, але не повторюючись?