gpt4 book ai didi

c# - 组合 monad(以 IEnumerable 和 Maybe 为例)

转载 作者:太空狗 更新时间:2023-10-29 18:00:19 28 4
gpt4 key购买 nike

我有一个一般性问题和一个更具体的案例问题。

通常如何组合不同的单子(monad)? monad 运算符的某种组合是否允许简单的组合?或者是否必须编写临时方法来组合每对可能的 monad?

作为一个具体的例子,我写了一个 Maybe monad。如何使用 IEnumerable<IMaybe<T>> ?除了在 LINQ 扩展中手动挖掘 Maybe monad(例如:if(maybe.HasValue) ... 在 select 子句中),是否有一种“monadic”方式将两者与各自的 Bind 等 monad 操作结合起来?

否则,如果我必须编写特定的组合方法,这样的方法是否正确?

    public static IEnumerable<B> SelectMany<A, B>(this IEnumerable<A> sequence, Func<A, IMaybe<B>> func)
{
return from item in sequence
let result = func(item)
where result.HasValue
select result.Value;
}


public static IEnumerable<C> SelectMany<A, B, C>(this IEnumerable<A> sequence, Func<A, IMaybe<B>> func, Func<A, B, C> selector)
{
return from item in sequence
let value = item
let maybe = func(item)
where maybe.HasValue
select selector(value, maybe.Value);
}

最佳答案

好问题!

monad 转换器 是一种向任意基础 monad 添加一些功能,同时保留 monad 特性的类型。遗憾的是,monad 转换器在 C# 中无法表达,因为它们必须使用更高级的类型。所以,在 Haskell 中工作,

class MonadTrans (t :: (* -> *) -> (* -> *)) where
lift :: Monad m => m a -> t m a
transform :: Monad m :- Monad (t m)

让我们一行一行地看一遍。第一行声明一个 monad 转换器是一个 t 类型,它接受一个类型为 * -> * 的参数(也就是说,一个需要一个参数的类型)并将其转换变成另一种类型的 * -> *。当您意识到所有 monad 都具有 * -> * 类型时,您会发现其意图是 t 将 monad 转换为其他 monad。

下一行表示所有 monad 转换器必须支持 lift 操作,该操作接受任意 monad m 并将其lifts 到转换器的世界 t m

最后,transform 方法表示对于任何 monad mt m 也必须是 monad。我正在使用来自 the constraints packageentailment 运算符 :- .


举个例子会更有意义。这是一个 monad 转换器,它将 Maybe-ness 添加到任意基础 monad mnothing 运算符允许我们中止计算。

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

nothing :: Monad m => MaybeT m a
nothing = MaybeT (return Nothing)

为了使 MaybeT 成为 monad 转换器,只要它的参数是 monad,它就必须是 monad。

instance Monad m => Monad (MaybeT m) where
return = MaybeT . return . Just
MaybeT m >>= f = MaybeT $ m >>= maybe (return Nothing) (runMaybeT . f)

现在编写MonadTrans 实现。 lift 的实现将基本 monad 的返回值包装在 Just 中。 transform 的实现很无趣;它只是告诉 GHC 的约束求解器验证 MaybeT 确实是一个 monad,只要它的参数是。

instance MonadTrans MaybeT where
lift = MaybeT . fmap Just
transform = Sub Dict

现在我们可以编写一个 monadic 计算,它使用 MaybeT 将失败添加到例如 State monad。 lift 允许我们使用标准的 State 方法 getput,但我们也可以访问 nothing 如果我们需要使计算失败。 (我考虑过使用您的 IEnumerable 示例(又名 []),但是向已经支持它的 monad 添加失败是有悖常理的。)

example :: MaybeT (State Int) ()
example = do
x <- lift get
if x < 0
then nothing
else lift $ put (x - 1)

使 monad 转换器真正有用的是它们的可堆叠性。这允许您从许多每个具有一种功能的小 monad 中组合出具有多种功能的大 monad。例如,给定的应用程序可能需要执行 IO、读取配置变量和抛出异常;这将使用类似

的类型进行编码
type Application = ExceptT AppError (ReaderT AppConfig IO)

the mtl package里面有工具这有助于您抽象出给定堆栈中 monad 转换器的精确集合和顺序,从而允许您省略对 lift 的调用。

关于c# - 组合 monad(以 IEnumerable 和 Maybe 为例),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8076628/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com