【问题标题】:Haskell can't deduce type equalityHaskell 无法推断类型相等
【发布时间】:2013-02-06 17:04:31
【问题描述】:

我有以下代码,但无法编译:

  import Numeric.AD

  data Trainable a b = forall n . Floating n =>  Trainable ([n] -> a -> b) (a -> b -> [n] -> n) 

  trainSgdFull :: (Floating n, Ord n) => Trainable a b -> [n] -> a -> b -> [[n]]
  trainSgdFull (Trainable _ cost) init input target =  gradientDescent (cost input target) init

我想使用 Trainable 类型来表示可通过梯度下降训练的机器学习系统。第一个参数是传递函数,第二个参数是成本函数,a 是输入类型,b 是输出/目标类型,列表包含可学习的参数。 编译器抱怨这个:

 src/MachineLearning/Training.hs:12:73:
Could not deduce (n1 ~ ad-3.3.1.1:Numeric.AD.Internal.Types.AD s n)
from the context (Floating n, Ord n)
  bound by the type signature for
             trainSgdFull :: (Floating n, Ord n) =>
                             Trainable a b -> [n] -> a -> b -> [[n]]
  at src/MachineLearning/Training.hs:12:3-95
or from (Floating n1)
  bound by a pattern with constructor
             Trainable :: forall a b n.
                          Floating n =>
                          ([n] -> a -> b) -> (a -> b -> [n] -> n) -> Trainable a b,
           in an equation for `trainSgdFull'
  at src/MachineLearning/Training.hs:12:17-32
or from (Numeric.AD.Internal.Classes.Mode s)
  bound by a type expected by the context:
             Numeric.AD.Internal.Classes.Mode s =>
             [ad-3.3.1.1:Numeric.AD.Internal.Types.AD s n]
             -> ad-3.3.1.1:Numeric.AD.Internal.Types.AD s n
  at src/MachineLearning/Training.hs:12:56-95
  `n1' is a rigid type variable bound by
       a pattern with constructor
         Trainable :: forall a b n.
                      Floating n =>
                      ([n] -> a -> b) -> (a -> b -> [n] -> n) -> Trainable a b,
       in an equation for `trainSgdFull'
       at src/MachineLearning/Training.hs:12:17
Expected type: [ad-3.3.1.1:Numeric.AD.Internal.Types.AD s n1]
               -> ad-3.3.1.1:Numeric.AD.Internal.Types.AD s n1
  Actual type: [n] -> n
In the return type of a call of `cost'
In the first argument of `gradientDescent', namely
  `(cost input target)'

基本概念对吗?如果是,我怎样才能使代码编译?

【问题讨论】:

  • 为什么需要forall?为什么不使用data Trainable a b n = Trainable ([n] -> a -> b) (a -> b -> [n] -> n)trainSgdFull :: (Floating n, Ord n) => Trainable a b n -> [n] -> a -> b -> [[n]]?这行得通吗?
  • 或者(看过 Numeric.AD)您是否需要trainSgdFull :: forall n.(Floating n, Ord n) => Trainable a b n -> [n] -> a -> b -> [[n]]
  • 我想避免在 Trainable 类型构造函数中使用 n,因为我希望同一个 Trainable 能够与 Doubles 和 AD 类型一起使用。
  • 给定gradientDescent = undfined的定义,您的代码对我来说是按原样编译的。需要更多的上下文。 (AFAICT gradientDescent 不在 Numeric.AD 中)。
  • 根据Hackage,ghci gradientDescent在Numeric.AD中。它可以用 undefined 编译,因为 undefined 将简单地匹配任何类型。

标签: haskell automatic-differentiation


【解决方案1】:

问题是

data Trainable a b = forall n . Floating n =>  Trainable ([n] -> a -> b) (a -> b -> [n] -> n)

表示在

Trainable transfer cost

使用的类型n 丢失。所知道的是,有一些类型 Guessme 带有 Floating 实例,这样

transfer :: [Guessme] -> a -> b
cost :: a -> b -> [Guessme] -> Guessme

您可以使用仅适用于Complex Float、或仅适用于Double 或...的功能构建Trainables,或...

但是在

trainSgdFull :: (Floating n, Ord n) => Trainable a b -> [n] -> a -> b -> [[n]]
trainSgdFull (Trainable _ cost) init input target =  gradientDescent (cost input target) init

您正在尝试将 cost 与作为参数提供的任何 Floating 类型一起使用。

Trainable 是为使用 n0 类型而构建的,用户提供类型 n1,它们可能相同也可能不同。因此编译器无法推断它们是相同的。

如果你不想让n 成为Trainable 的类型参数,你需要让它包装与每个 Floating 调用者提供的类型一起工作的多态函数 p>

data Trainable a b
    = Trainable (forall n. Floating n => [n] -> a -> b)
                (forall n. Floating n => a -> b -> [n] -> n)

(需要Rank2Types,或者,因为它正在被弃用,所以需要RankNTypes)。

【讨论】:

  • OP 可能一直想包装一个多态类型,但最终却是一个存在,因为我们在 Haskell 中使用 forall 而不是 exists。我每次都掉进这个陷阱。
  • 谢谢你的回答,它适用于这个模块,但我有一个后续question@n.m。是的,我真的想要多态类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-22
相关资源
最近更新 更多