(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 GT
kasing dimasukkan, kami tahu pasti bahwa nilai pengembalian akhir akan menjadi Just
sesuatu yang bukan Nothing
, tetapi Just
masih belum tersedia sampai akhir. Saya ingin membuat ini lebih malas sehingga Just
tersedia segera setelah GT
kasing dimasukkan. Kasus pengujian saya untuk ini adalah bahwa saya ingin Data.Maybe.isJust $ closestLess 5 (Node 3 () Leaf undefined)
mengevaluasi True
daripada 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 closestLess
dan di precise
. Bagaimana saya bisa menulis ini sehingga malas tetapi tanpa mengulangi sendiri?