как запустить произвольное количество поколений в задаче вторжения кролика - PullRequest
1 голос
/ 04 октября 2019

Я работаю над проблемой в викибуке на haskell и полностью застрял. Они просят «Обобщить пример вторжения кролика в главе с монадой списка для произвольного числа поколений».

Описание примера вторжения кролика:

«Легко включить знакомоеФункции обработки списков в монадическом коде. Рассмотрим этот пример: кролики собирают в среднем шесть комплектов в каждом помете, половина из которых будет самкой. Начиная с матери-одиночки, мы можем смоделировать количество комплектов самок в каждом последующем поколении (т.е. количество новых наборов после того, как кролики вырастут и будут иметь свои собственные пометы): "

Prelude> let generation = replicate 3
Prelude> ["bunny"] >>= generation
["bunny","bunny","bunny"]
Prelude> ["bunny"] >>= generation >>= generation
["bunny","bunny","bunny","bunny","bunny","bunny","bunny","bunny","bunny"]

Моя попытка генерирует вложенные списки вместо плоского списка

В этой главе упоминаются функции, которыеЯ предполагаю, что должен использовать в том числе: sequence, replicate, replicateM, mapM, forM и их версии подчеркивания, которые не передают контекст следующей связанной монаде.

["bunny"] >>= replicateM 2 gen

Я получаю

[["bunny","bunny","bunny"],["bunny","bunny","bunny"]]

но это должно быть

["bunny","bunny","bunny","bunny","bunny","bunny","bunny","bunny","bunny"]

1 Ответ

2 голосов
/ 04 октября 2019

Вы можете использовать nest :: Monad m => Int -> (a -> m a) -> a -> m a или реализовать это самостоятельно. nest использует foldM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b, где передается список «единиц» ():

nest :: (Monad m) => Int -> (a -> m a) -> a -> m a
nest n f x0 = M.foldM (\x () -> f x) x0 (List.replicate n ())</blockquote>

тогда это работает с:

Prelude Control.Monad.HT> nest 2 generation "bunny"
["bunny","bunny","bunny","bunny","bunny","bunny","bunny","bunny","bunny"]

Обратите внимание, что начальным значением является не список "bunny", а сам "bunny".

Мы можем реализовать функциюнапример, через foldl рекурсию:

foldN :: Monad m => Int -> (a -> m a) -> m a -> m a
foldN n x0 = foldl (>>=) x0 . replicate n

Затем мы получим:

Prelude Control.Monad> foldN 2 ["bunny"] generation
["bunny","bunny","bunny","bunny","bunny","bunny","bunny","bunny","bunny"]

мы можем, как @ DanielWagner говорит , определить это с помощью рекурсии с:

import Control.Monad(>=>)

manyGenerations :: Integral n => n -> [a] -> [a]
manyGenerations 0 = id
manyGenerations n = generation >=> manyGenerations (n-1)
...