(не совсем ответ на вопрос, но связанный)
Мне нравится представлять деревья как "ListT [] a
". (ListT
из пакета List
во взломе)
Тогда ответом на этот вопрос является использование функции lastL
.
"Monad m => ListT m a
" - это монадический список, содержащий "a
", где попытка получить следующий элемент списка (который может обнаружить, что такого элемента нет) является монадическим действием в "m
".
Пример использования для ListT
- программа, которая читает числа от пользователя до тех пор, пока пользователь не наберет число и напечатает сумму чисел после каждого ввода:
main =
execute . joinM . fmap print .
scanl (+) 0 .
fmap (fst . head) .
takeWhile (not . null) .
fmap reads .
joinM $ (repeat getLine :: ListT IO (IO String))
Где repeat
, scanl
и takeWhile
от Data.List.Class
. Они работают как для обычных, так и для монадических списков.
joinM :: List l => l (ItemM l a) -> l a -- (l = ListT IO, ItemM l = IO)
execute :: List l => l a -> ItemM l () -- consume the whole list and run its actions
Если вы знакомы с Python, итераторы / генераторы python являются "ListT IO
" s.
При использовании []
вместо IO
в качестве монады монадического списка, получается дерево. Зачем? Представьте себе список, в котором получение следующего элемента является действием в монаде списка - монада списка означает, что есть несколько опций, поэтому существует несколько «следующих элементов», что делает его деревом.
Вы можете создавать монадические списки либо с помощью функций более высокого порядка (как в примере выше), либо с cons
, либо с помощью нотации генератора питона (с yield
), используя монадный преобразователь GeneratorT
из generator
упаковка в взломе.
Отказ от ответственности: ListT
и GeneratorT
никоим образом не используются широко. Я написал их, и я не знаю других пользователей, кроме себя. Есть несколько пользователей эквивалентных ListT
s, таких как пользователь из вики Haskell, NondetT
и другие.