Haskell 应用程序和 ErrorT?

发布于 2024-08-25 11:40:34 字数 340 浏览 6 评论 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 以便它按我的预期工作?

Why is it that I can do the following:

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

getW1 :: ErrorT String Get Word8
getW1 = lift getWord8

f1 = (+1) <
gt; getW1

but I cannot do:

f2 = (+) <
gt; getW1 <*> getW1

and how I do I modify f2 so that it will work as I intend?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

メ斷腸人バ 2024-09-01 11:40:34

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

{-# LANGUAGE FlexibleInstances #-}

instance (Error e, Monad m) => Applicative (ErrorT e m) where
    pure = return
    (<*>) = ap

<$> only requires that ErrorT String Get to be an instance of Functor. <*> requires that it be an instance of Applicative. I think this instance declaration should work:

{-# LANGUAGE FlexibleInstances #-}

instance (Error e, Monad m) => Applicative (ErrorT e m) where
    pure = return
    (<*>) = ap
情归归情 2024-09-01 11:40:34

要进行错误处理,您不一定需要 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 $ (+) <
gt; getM1 <*> getM1    -- D "2"
    --
    runApplicative $ (+) <
gt; getA  <*> getA   -- D "2"
    runApplicative $ (+) <
gt; getE  <*> getA   -- D "bad"
    runApplicative $ (+) <
gt; getE  <*> getE   -- D "badbad"
    --
    runOtherApp    $ (+) <
gt; getA2 <*> getA2  -- "D 2"
    runOtherApp    $ (+) <
gt; 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

To do error handling, you don't necessary need the Either(T) monad. You can be perfectly fine by staying in Applicative via composition. Example (for fun using AccValidation which accumulates all errors):

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 $ (+) <
gt; getM1 <*> getM1    -- D "2"
    --
    runApplicative $ (+) <
gt; getA  <*> getA   -- D "2"
    runApplicative $ (+) <
gt; getE  <*> getA   -- D "bad"
    runApplicative $ (+) <
gt; getE  <*> getE   -- D "badbad"
    --
    runOtherApp    $ (+) <
gt; getA2 <*> getA2  -- "D 2"
    runOtherApp    $ (+) <
gt; 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文