绑定到Haskell中数据结构内部的monad

绑定到Haskell中数据结构内部的monad,haskell,Haskell,有没有一种定义绑定的方法只影响数据结构的一部分 例如,假设我们有一个模拟计算数据类型,它有一个名称和一个结果 type Name = String data Error = TimeOut | NotEnoughMemory | DivByZero type Result a = Either Error a data Computation a = Computation Name (Result a) 由于计算可能会失败,但我们可能仍然对它的名称

有没有一种定义绑定的方法只影响数据结构的一部分

例如,假设我们有一个模拟计算数据类型,它有一个名称和一个结果

type Name          = String
data Error         = TimeOut | NotEnoughMemory | DivByZero
type Result a      = Either Error a
data Computation a = Computation Name (Result a)

由于计算可能会失败,但我们可能仍然对它的名称感兴趣,它不能是结果的一部分,必须是计算的一部分。另一方面,直接绑定和验证计算结果也很方便,就像使用常规类型一样。有办法吗?

不,您可能无法定义任何有用的
实例Monad计算
,因为您无法从
Applicative
类(它是
Monad
的超类)中定义
pure::a->Computation a
;如果只给
a
类型的值,您将如何实例化
名称

但它是一个
函子
(您可以自动派生它)。有了更多的上下文,可能会有一个更有用的不同抽象。

TW

我想你可能想要

type Computation = ExceptT Error (Writer Name)

-- in familiar types:
-- Computation a ⋍ (Either Error a, Name)
注意,
Name
现在必须是
Monoid
。这是有道理的,因为

liftA2 (+) comp1 comp2
,它添加了两个子计算的结果,还需要有一个名称。
Writer
组件所做的是连接(使用monoid的
——因此不一定只是字符串连接)两个子计算的名称。例如,您可能会使用:

newtype Name = Name [String]
    deriving (Semigroup, Monoid)
two :: Computation Int
two = name "two" $ pure 2

someComp :: Computation Int
someComp = name "two plus two" $ liftA2 (+) two two
您可能还需要一种方法来定义某些计算的名称:

name :: String -> Computation a -> Computation a
name n = mapExceptT (censor (const (Name [n])))
例如:

newtype Name = Name [String]
    deriving (Semigroup, Monoid)
two :: Computation Int
two = name "two" $ pure 2

someComp :: Computation Int
someComp = name "two plus two" $ liftA2 (+) two two

假设您要绑定一个计算,那么输出
计算
应该有哪个
名称
?使用
return
生成的
计算
应该有什么名称?
计算
看起来只是将名称绑定到某个匿名计算的结果,而不是表示任何计算本身。