2016-12-30 2 views
3

Как упоминалось в Hackage for Applicative Functors, они являются сильными слабыми моноидальными функторами. Так почему же не их определение в Haskell показать это примерно так:Аппликативные функторы как моноидальные функторы

class Functor f => MonoidalApplicative f where 
    mult :: f a -> f b -> f (a,b) 
    unit :: a -> f a 

    starAp :: f (a -> b) -> f a -> f b 
    starAp h x = fmap (uncurry ($)) (mult h x) 

<*> (starAp) легко реконструируется с точки зрения умножения и это определение выглядит проще для меня. Для Exemple, здесь Может быть, пример:

instance MonoidalApplicative Maybe where 
    mult (Just x) (Just y) = Just (x,y) 
    mult _ _ = Nothing 

    unit x = Just x 
+6

Презентация '(<*>)' имеет тенденцию быть более удобной в повседневном программировании, хотя в некоторых аспектах «мульти» действительно более аккуратный (например, прикладные законы выглядят лучше, когда выражаются в его терминах). Этот сценарий аналогичен взаимосвязи между «(>> =)» и «join». Соответствующая запись в блоге: http://blog.ezyang.com/2012/08/applicative-functors/ – duplode

+4

Примечание: моноидальная презентация обычно имеет 'unit :: f()'. 'pure', то можно восстановить через' pure x = fmap (const x) unit'. – duplode

+2

См. Http://stackoverflow.com/a/27262462/414413 – Cirdec

ответ

4

Как было упомянуто в комментариях к ответу, есть похожая история с join и >>=. Когда есть несколько семантически эквивалентных способов определить что-то, лучше всегда выбирать наиболее эффективный прагматичный способ. Haskell был разработан, чтобы писать код, а не доказывать вещи (хотя, как-то Haskell до сих пор не стал очень популярным языком программирования).

Если starAp имеет реализацию по умолчанию, почти никто не будет реализовывать ее (как это происходит сейчас с >> в классе Monad). Но <*> - чрезвычайно полезная операция. Он используется в аппликате & монадических парсеров много (megaparsec, attoparsec, optparse-applicative), и я не могу представить себе свою жизнь без liftA* для присоединения к вещам. И очень важно, чтобы эта операция была максимально эффективной. Реализация starAp как fmap (uncurry ($)) (mult h x) может принести трудные времена для создания и оптимизации вещей для компилятора.

Кроме того, представление Applicative с использованием mult и unit операций на самом деле не решает проблем. Очевидно, mult = liftA2 (,). Но ваша реализация с

mult (Just x) (Just y) = Just (x,y)

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

+0

Но в случае Monad 'join' фактически предполагалось добавить в Monad с AMP. Это было связано не с техническими трудностями: http://stackoverflow.com/questions/31552064/why-isnt-join-part-of-the-monad-class/31552223 – jpath

+0

Так это просто проблема производительности? Тогда почему бы не объявить как 'mult', так и' <*>' в аппликативном порядке, каждый из которых вызывает другой, чтобы экземпляры могли выбрать, какой из них следует переопределять (или оба)? Кроме того, почти все вызовы, которые я видел в '<*>', полностью оцениваются, предоставляя столько значений, сколько функция имеет переменные. Например, с помощью функции с тремя переменными, я предпочитаю 'liftA3 f x y z' до' f <$> x <*> y <*> z'. Тогда ожидания производительности находятся на 'liftA3', а не' <*> '. –

+1

'liftA3 f x y z = f <$> x <*> y <*> z', эта функция не быстрее, чем' <*> '. И это может легко не полностью оценить. Пример: сумма двух может быть. 'liftA2 (+) Nothing (всего $ 2^(2^100))' мгновенно оценивается, а 'liftA2 (+) (Just 3) (Just $ 2^(2^100))' будет убивать вашу машину. Очень законный случай. Зачем определять, когда 'mult = liftA2 (,)' и такая реализация достаточно ленивая? Разрешение нескольких функций внутри одного класса типов является склонным к ошибкам подходом. Здесь вы можете увидеть другие объяснения: https://ghc.haskell.org/trac/ghc/wiki/Proposal/MonadOfNoReturn – Shersh

Смежные вопросы