首页 文章

类型问题与Haskell概率Monad

提问于
浏览
1

我试图在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)由它的歧义检查引起的'来自上下文(MonadDiscrete wm)的推断类型forit':MonadDiscrete wm => m [Char] at:7:1-17类型变量w0'是不明确的可能修复:添加一个修复这些类型变量的类型签名注意:有几个潜在的实例:实例Num w => MonadDiscrete w(离散w) - 在lib / Discrete.hs中定义:64: 10实例Control.Monad.Random.Class.MonadRandom m => MonadDiscrete Rational m - 在lib / Discrete.hs中定义:58:10当检查'具有推断类型`forall w(m :: * - > *)时 . MonadDiscrete w m => m [Char]'可能原因:推断类型不明确

我尝试了各种各样的事情,包括添加FunDeps或使w成为相关类型,但都失败了 .

2 回答

  • 0

    问题在于声明

    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 类型中没有出现 w ,它仍然可以唯一解析,因此可以选择正确的 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 实例的部分是说什么类型代表 Weight .

  • 1

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

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

    但反而:

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

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

相关问题