0

为什么我可以执行以下操作:

import Data.Word
import Data.Binary.Get
import Control.Applicative
import Control.Monad.Error

getW1 :: ErrorT String Get Word8
getW1 = lift getWord8

f1 = (+1) <$> getW1

但我不能这样做:

f2 = (+) <$> getW1 <*> getW1

以及如何修改 f2 以使其按预期工作?

4

2 回答 2

3

<$>只要求它ErrorT String GetFunctor. <*>要求它是 的一个实例Applicative。我认为这个实例声明应该有效:

{-# LANGUAGE FlexibleInstances #-}

instance (Error e, Monad m) => Applicative (ErrorT e m) where
    pure = return
    (<*>) = ap
于 2010-03-20T06:59:43.620 回答
0

要进行错误处理,您不需要Either(T)monad。你可以通过组合留在Applicative里面。示例(为了好玩,AccValidation它会累积所有错误):

import Control.Applicative
import Control.Monad.Error

import Data.Validation
import Data.Bifoldable
import Data.Functor.Compose

-- Replicating OP example with a Dummy monad (Get is made Applicative in newer libs)

data Dummy a = D a
  deriving Show

instance Monad Dummy where
  return = D
  (D x) >>= f = f x

instance Functor Dummy where
  fmap f (D x) = D (f x)

getM1 :: ErrorT String Dummy Int
getM1 = lift (D 1)

-- Can do with Applicatives + (Acc)Validation too

instance Applicative Dummy where
  pure = return
  (<*>) = ap

getA :: Compose Dummy (AccValidation String) Int
getA = Compose $ D (success 1)

getE :: Compose Dummy (AccValidation String) Int
getE = Compose $ D (failure "bad")

-- Applicative composition can work either way

getA2 :: Compose (AccValidation String) Dummy Int
getA2 = Compose $ success (D 1)

getE2 :: Compose (AccValidation String) Dummy Int
getE2 = Compose $ failure "bad"

main = do
    runMonadic $ (+) <$> getM1 <*> getM1    -- D "2"
    --
    runApplicative $ (+) <$> getA  <*> getA   -- D "2"
    runApplicative $ (+) <$> getE  <*> getA   -- D "bad"
    runApplicative $ (+) <$> getE  <*> getE   -- D "badbad"
    --
    runOtherApp    $ (+) <$> getA2 <*> getA2  -- "D 2"
    runOtherApp    $ (+) <$> getE2 <*> getE2  -- "badbad"
    where
      runMonadic      = print . fmap (either id show) . runErrorT
      runApplicative  = print . fmap (validate id show) . getCompose
      runOtherApp     = print . validate id show . getCompose

-- some helper mimicking @either@ of @Either@
validate :: (e -> c) -> (a -> c) -> AccValidation e a -> c
validate f g = bifoldl (const f) (const g) undefined
于 2013-01-15T17:19:40.053 回答