【问题标题】:Typeclass Trouble with Haskell Probability MonadHaskell概率单子的类型类问题
【发布时间】:2014-11-12 06:21:16
【问题描述】:

我正在尝试在 haskell 中为离散随机变量编写一个 monad。类型类看起来像这样:

{- LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}

class (Num w, Monad m) => MonadDiscrete w m where
  sample :: [(a, w)] -> m a

我想为此做两个实例。第一个就像 list monad:

newtype Discrete w a = Discrete [(a, w)]

instance (Num w) => Monad (Discrete w) where
  ...

instance (Num w) => MonadDiscrete w (Discrete w) where
  sample = Discrete

第二个是在 MonadRandom 中使用 PRNG:

instance (MonadRandom m) => MonadDiscrete Rational m where
  sample = fromList

但是,如果我尝试执行以下操作:

x :: (Num w, MonadDiscrete w m) => m String
x = sample [("x", 1)]

GHC 给我一个错误:

无法推断 (MonadDiscrete w0 m) 由 it' from the context (MonadDiscrete w m) bound by the inferred type forit' 的歧义检查引起:MonadDiscrete w m => m [Char] 在:7:1-17 类型变量w0' is ambiguous Possible fix: add a type signature that fixes these type variable(s) Note: there are several potential instances: instance Num w => MonadDiscrete w (Discrete w) -- Defined at lib/Discrete.hs:64:10 instance Control.Monad.Random.Class.MonadRandom m => MonadDiscrete Rational m -- Defined at lib/Discrete.hs:58:10 When checking thatit' 具有推断类型`forall w (m :: * -> *)。 MonadDiscrete w m => m [字符]' 可能原因:推断类型不明确

我尝试了各种方法,包括添加 FunDeps 或使 w 成为关联类型,但都失败了。

【问题讨论】:

  • 你能修复你的代码示例吗? MonadDiscrete (Discrete w) 的实例需要另一个类型参数...也就是说,您是否尝试过消除 x 中的常量 1 的歧义,例如:(1::Int)
  • 答案将是FunctionalDependencies

标签: haskell monads typeclass


【解决方案1】:

问题在于声明

class (Num w, Monad m) => MonadDiscrete w m where
    sample :: [(a, w)] -> m a

没有表示对于给定的离散概率单子,表示权重的类型选择是固定的。例如,在您的Discrete 示例中,对于w 的任何选择,Discrete w monad 只能处理w 类型的概率权重。

因为这在上面的声明中没有表达出来,所以可以定义两个MonadDiscrete实例,它们只在w的选择上不同,而在m的选择上没有区别。这表示 在sample的定义中,MonadDiscrete实例不能单独从m解析。

解决这个问题的正确方法是使用函数依赖或MonadDiscrete相关类型族来表达m的选择唯一决定w的选择这一事实。下面是一个使用函数依赖的例子:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies #-}

class (Num w, Monad m) => MonadDiscrete w m | m -> w where
    sample :: [(a, w)] -> m a

newtype Discrete w a = Discrete [(a, w)]

instance (Num w) => Monad (Discrete w)
instance (Num w) => MonadDiscrete w (Discrete w)

x :: (Num w, MonadDiscrete w m) => m String
x = sample [("x", 1)]

因为m决定了w,所以即使w没有出现在x的类型中,它仍然可以唯一解析,因此可以选择正确的MonadDiscrete实例。

这是使用类型族的相同解决方案:

{-# LANGUAGE TypeFamilies, FlexibleContexts #-}

class (Num (Weight m), Monad m) => MonadDiscrete m where
    type Weight m :: *
    sample :: [(a, Weight m)] -> m a

newtype Discrete w a = Discrete [(a, w)]

instance (Num w) => Monad (Discrete w)

instance (Num w) => MonadDiscrete (Discrete w) where
    type Weight (Discrete w) = w
    sample = undefined

x :: (MonadDiscrete m) => m String
x = sample [("x", 1)]

这个感觉有点不同,因为这里没有说明依赖关系,我们只是说MonadDiscrete 实例的一部分是说明什么类型代表Weights。

【讨论】:

  • 请您给出一个使用类型族的等效公式?
  • 完成;但我觉得fundep 更接近弗拉德的原始代码。
  • 您没有包含第二个 (MonadRandom m) 实例。添加这会导致 ghc 抱怨:“MonadDiscrete Rational m 的重叠实例”。类型族也会发生类似的错误。有没有办法解决这个问题?
  • 考虑当有人为Discrete 添加MonadRandom 实例时会发生什么...查看Control.Applicative.WrappedMonad 以了解此类问题的解决方法。
  • 我认为问题在于,实际上我想说的是“如果它还不是 MonadDiscrete,而是 MonadRandom,那么使用它使其成为 MonadDiscrete”,但是这个在 Haskell 中并不能真正表达。这个问题导致我阅读了关于类型类的各种内容。我已经发现了这些“ConstraintKinds”,但还没有很好地了解它们以确定它们是否适用于这里(iirc 它们允许你做一些你以前无法做到的事情,比如设置一个 Monad)。
【解决方案2】:

我想我已经发现我实际上并不想要

instance (MonadRandom m) => MonadDiscrete Rational m where
  sample = fromList

但是:

instance RandomGen g => MonadDiscrete Rational (Rand g) where
  sample = fromList

因为我的目标是使用特定的现有实现,而不是所有可能的 MonadRandom 实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-19
    • 2010-12-29
    • 1970-01-01
    • 2015-07-03
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多