Можно ли написать этот код без использования нотации?
У меня есть какая-то функция
bar :: MyType -> MyType -> [MyType]
Я хотел бы иметь другую функцию:
foo :: [MyType] -> [MyType]
foo xs = do x <- xs
y <- xs
bar x y
Можно ли написать foo
без использования do
нотация? Я думал о чем-то вроде liftA2
но это не сработает.
2 ответа
Решение
Мы можем использовать алгоритмическое преобразование из do-блоков, как описано в отчете Haskell:
foo :: [MType] -> [MType]
foo xs = xs >>= \x -> xs >>= \y -> bar x y
Но мы можем уменьшить количество лямбда-выражений, опуская y
переменная:
foo :: [MType] -> [MType]
foo xs = xs >>= \x -> xs >>= bar x
и мы можем опустить x
переменная, а также, написав \x -> xs >>= bar x
как (xs >>=) . bar
foo :: [MType] -> [MType]
foo xs = xs >>= ((xs >>=) . bar)
Или, как говорит @ М. Аруси, мы можем использовать комбинацию join :: Monad m => m (m a) -> m a
а также liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
:
foo :: [MType] -> [MType]
foo xs = join (liftA2 bar xs xs)
Вы также можете использовать следующую схему для bar
:
Арити 2
-- bar :: [MType] -> [MType]
foo :: [MType] -> [MType]
foo xs = join $ bar <$> xs <*> xs
Арити 3
-- bar :: [MType] -> [MType] -> [MType]
foo :: [MType] -> [MType]
foo xs = join $ bar <$> xs <*> xs <*> xs
и так далее.
Мне это нравится, так как его проще расширить, чем жестко liftA2
,