我正在尝试在haskell中为离散随机变量编写一个monad。类型类看起来像这样:
{- LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
class (Num w, Monad m) => MonadDiscrete w m where
sample :: [(a, w)] -> m a
我想做两个这样的例子。第一个就像列表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 for
的歧义检查引起的:#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 that
它' 具有推断类型`forall w(m :: * - > *)。 MonadDiscrete w m => m [Char]' 可能原因:推断类型不明确
我尝试了各种各样的事情,包括添加FunDeps或制作相关类型,但都失败了。
答案 0 :(得分:1)
问题在于声明
class (Num w, Monad m) => MonadDiscrete w m where
sample :: [(a, w)] -> m a
没有表达这样的事实:对于给定的离散概率monad,表示权重的类型的选择是固定的。例如,在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
,它仍然可以唯一解析,所以正确{{1}可以选择实例。
以下是使用类型系列的相同解决方案:
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
s。
答案 1 :(得分:0)
我想我已经发现我实际上并不想要
instance (MonadRandom m) => MonadDiscrete Rational m where
sample = fromList
但相反:
instance RandomGen g => MonadDiscrete Rational (Rand g) where
sample = fromList
由于我的目标是使用特定的现有实现,而不是所有可能的MonadRandom实例。