(Terinspirasi oleh jawaban saya untuk pertanyaan ini .)
Pertimbangkan kode ini (seharusnya menemukan elemen terbesar yang kurang dari atau sama dengan input yang diberikan):
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
Ini tidak terlalu malas. Setelah GTkasing dimasukkan, kami tahu pasti bahwa nilai pengembalian akhir akan menjadi Justsesuatu yang bukan Nothing, tetapi Justmasih belum tersedia sampai akhir. Saya ingin membuat ini lebih malas sehingga Justtersedia segera setelah GTkasing dimasukkan. Kasus pengujian saya untuk ini adalah bahwa saya ingin Data.Maybe.isJust $ closestLess 5 (Node 3 () Leaf undefined)mengevaluasi Truedaripada bottoming. Inilah satu cara yang bisa saya pikirkan untuk melakukan ini:
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
Namun, saya sekarang mengulangi diri saya sendiri: logika inti sekarang ada di dalam closestLessdan di precise. Bagaimana saya bisa menulis ini sehingga malas tetapi tanpa mengulangi sendiri?