2010-12-11 3 views
1

Как написать функцию, которая выполняет логические и функции между элементами списка?Haskell IO Bool fold question

Я написал это:

iand :: [IO Bool] -> IO Bool 

iand [] = return (True) 
iand (x:xs) = do 
    a <- x 
    b <- iand(xs) 
    return (a && b) 

Но это, кажется, unconscice.

Как эту функцию можно переписать с помощью foldM (liftM)?

спасибо.

ответ

10

Функция Prelude and :: [Bool] -> Bool почти делает то, что вы хотите, но это не монадическая. Вообще говоря, чтобы поднять функцию одного аргумента в монаду, вам понадобится Control.Monad's liftM :: Monad m => (a -> b) -> m a -> b a; однако, чтобы быть более общим, вы можете использовать Prelude's fmap :: Functor f => (a -> b) -> f a -> f b. Все монады являются функторами , так что это нормально. Таким образом, вы можете использовать

fand' :: Functor f => f [Bool] -> f Bool 
fand' = fmap and 

Однако, по крайней мере, 90% времени, я бы просто написать, что встроенный в fmap and xs, или более вероятно and <$> xs, используя <$> синоним Control.Applicative для fmap.

Конечно, я уверен, что вы заметили, что это не то, что вы хотите. Для этого вам нужен Prelude sequence :: Monad m => [m a] -> m [a]. Теперь у вас есть функция [m a] -> m [a] и функция f [Bool] -> f Bool, так что мы можем объединить эти:

mand :: Monad m => [m Bool] -> m Bool 
mand = liftM and . sequence 

я перешел на liftM из fmap, потому что, хотя fmap «ы„лучше“в каком-то смысле, это было бы наложить дополнительные Functor m ограничение. То, что не должно быть, может быть проблемой, но это может быть по историческим причинам, поэтому я играл в нее безопасно.

Кроме того, вы можете спросить: «Как бы я узнал о sequence»? Ответ на этот вопрос - замечательный Hoogle, который позволяет вам искать функции Haskell по названию или типа. Итак, поскольку вы знали о liftM :: Monad m => (a -> b) -> m a -> m b, возможно, вы поняли, что вам нужно что-то вроде Monad m => [m a] -> m [a]; Hoogling для этого does indeed turn up sequence.


1: Или, по крайней мере, они должны быть, по историческим причинам, однако, это не всегда так.

+0

Спасибо!Но он говорит: «Не удалось сопоставить ожидаемый тип' m »с предполагаемым типом' [] '' для функции mand. В чем проблема? – 4DA

+0

@Dmitry: Ой, это потому, что я опечатал. Я утверждал, что 'mand :: Monad m => m [Bool] -> m Bool', что, очевидно, глупо, так как * point * этого упражнения состояла в том, чтобы построить вам функцию с типом' Monad m => [m Bool ] -> m Bool'. Если вы исправите это утверждение типа, все будет работать. Я отредактировал свой ответ соответственно. –

1

Это не было iand list = foldl (&&) True list?

+0

Нет. Это будет функция типа '[Bool] -> Bool', которая действует как обычный' и ', но менее ленив. То, что хочет Дмитрий, является функцией типа '[IO Bool] -> IO Bool'. – sepp2k

+0

Справа. Пропустил это. Извините за путаницу. –

2

Вы можете использовать liftM превратить and (который имеет тип [Bool] -> Bool) в зависимости от типа IO [Bool] -> IO Bool и sequence, чтобы превратить ваш [IO Bool] в IO [Bool].

Так что ваша функция становится:

iand ibs = liftM and (sequence ibs)