Как определить применение с точки зрения привязки? - PullRequest
2 голосов
/ 10 ноября 2019

В Haskell Applicative считаются более сильными, чем Functor, что означает, что мы можем определить Functor, используя Applicative, например

-- Functor
fmap :: (a -> b) -> f a -> f b
fmap f fa = pure f <*> fa

, а монады считаются более сильными, чем Applicatives & Functors, что означает.

-- Functor
fmap :: (a -> b) -> f a -> f b
fmap f fa = fa >>= return . f

-- Applicative
pure :: a -> f a
pure = return

(<*>) :: f (a -> b) -> f a -> f b
(<*>) = ???  -- Can we define this in terms return & bind? without using "ap" 

Я прочитал, что монады для последовательности действий. Но я чувствую, что единственное, что может сделать Монада, - это Join или Flatten, а остальная часть его возможностей исходит от Applicatives.

join :: m (m a) -> m a
-- & where is the sequencing in this part? I don't get it.

Если Monad действительно предназначен для последовательных действий, то почему мы можем определить аппликативы (которые не считаются строго работающими в последовательности, какие-то параллельные вычисления)?

Как монадыМоноиды в категории эндофункторов. Также есть коммутативные моноиды, которые не обязательно должны работать по порядку. Это означает, что экземпляры Монады для Коммутативных Моноидов также должны быть упорядочены?

Редактировать: Я нашел отличную страницу http://wiki.haskell.org/What_a_Monad_is_not

Ответы [ 3 ]

5 голосов
/ 10 ноября 2019

Если Monad действительно для последовательных действий, то почему мы можем определить Прилагательные (которые не считаются строго работающими в последовательности, своего рода параллельные вычисления)?

Не совсем. Все монады являются аппликативными, но только некоторые аппликативные являются монадами. Поэтому, учитывая монаду, вы всегда можете определить аппликативный экземпляр в терминах bind и return, но если все, что у вас есть, это аппликативный экземпляр, то вы не можете определить монаду без дополнительной информации.

Аппликативный экземплярдля монады это будет выглядеть так:

instance (Monad m) => Applicative m where
   pure = return
   f <*> v = do
      f' <- f
      v' <- v
      return $ f' v'

Конечно, это последовательно оценивает f и v, потому что это монада, и именно это делают монады. Если этот аппликативный код не выполняет действия в последовательности, он не является монадой.

Современный Haskell, конечно, определяет это наоборот: класс типов Applicative является подмножеством Functor, поэтомуесли у вас есть Functor и вы можете определить (<*>), тогда вы можете создать Applicative экземпляр. Monad в свою очередь определяется как подмножество Applicative, поэтому, если у вас есть экземпляр Applicative и вы можете определить (>>=), вы можете создать экземпляр Monad. Но вы не можете определить (>>=) в терминах (<*>).

См. Typeclassopedia для получения более подробной информации.

4 голосов
/ 10 ноября 2019

Мы можем скопировать определение ap и отменить его:

ap f a = do
   xf <- f
   xa <- a
   return (xf xa)

Следовательно,

f <*> a = f >>= (\xf -> a >>= (\xa -> return (xf xa)))

(Несколько избыточных скобок добавлены для ясности.)

1 голос
/ 10 ноября 2019

(<*>) :: f (a -> b) -> fa -> fb

(<*>) = ??? - Можем ли мы определить это с точки зрения возврата и связывания? без использования "ap"

Напомним, что <*> имеет сигнатуру типа f (a -> b) -> f a -> f b, а >> имеет m a -> (a -> m b) -> m b. Итак, как мы можем вывести m (a -> b) -> m a -> m b из m a -> (a -> m b) -> m b?

Чтобы определить f <*> x с помощью >>=, первый параметр >>= должен быть, очевидно, f, поэтому мы можем записать первое преобразование:

f <*> x = f >>= k      -- k to be defined

, где функцияk принимает в качестве параметра функцию с типом a -> b и возвращает результат m b, так что все определение совпадает с сигнатурой типа bind >>=. Для k мы можем написать:

k :: (a -> b) -> m b
k = \xf -> h x          

Обратите внимание, что функция h должна использовать x из f <*> x, поскольку x каким-то образом относится к результату m bнапример, функция xf из a -> b.

Для h x легко получить:

h :: m a -> m b
h x = x >>= return . xf

Соедините три вышеприведенных определения, и мы получим:

f <*> x = f >>= \xf -> x >>= return . xf

Таким образом, даже если вы не знаете определения ap, вы все равно можете получить конечный результат, показанный @chi в соответствии с сигнатурой типа.

...