Использование Foldr и Bind, чтобы завершить ничто

Итак, по сути, у меня есть некоторая монадическая функция, завернутая в MaybeT Я хочу использовать Nothing в качестве завершающего случая для рекурсии

Мое понимание foldr является то, что, если он может произвести результат, не занимая весь список, он может безопасно использоваться в бесконечном списке, т.е. foldr (&&) True $ repeat False все еще может вернуться False,

На данный момент у меня есть:

repeaterM a f = foldr (=<<) (return a) $ repeat f

Этот тип проверяет, но на самом деле не работает. Может ли кто-нибудь объяснить мне, почему я не могу использовать эту функцию, чтобы неоднократно применять функцию к ее собственному результату, пока она не вернется Nothing?

1 ответ

foldr            :: (a -> b -> b) -> b -> [a] -> b
foldr k z = go
          where
            go []     = z
            go (y:ys) = y `k` go ys

Так

foldr (&&) True $ repeat False
   = go (repeat False) where go [] = True ; go (y:ys) = y && go ys
   = False && go (repeat False) where go [] = True ; go (y:ys) = y && go ys
   = False

как вы ожидаете.

Но

foldr (=<<) (return a) $ repeat f
   = go (repeat f) where go [] = return a ; go (y:ys) = y =<< ys
   = f =<< go (repeat f) where go [] = return a ; go (y:ys) = y =<< ys
   = f =<< f =<< go (repeat f) where go [] = return a ; go (y:ys) = y =<< ys
   = f =<< f =<< f =<< go (repeat f) where go [] = return a ; go (y:ys) = y =<< ys
   ...

То, что вы делаете здесь, не повторяет применение функции к ее собственному результату, пока она не вернется Nothing,

Вы строите вычисления с его конца: RHS каждого =<< должен быть рассчитан до того, как LHS может быть выполнен. Но у вас есть бесконечный список, поэтому вы никогда не доберетесь до начала вычислений.

Вы можете попытаться определить

repeaterM a f = foldl (>>=) (return a) $ repeat f

вместо. Это тоже не сработает (спасибо is7s).

Другие вопросы по тегам