为什么一个函数只能被一个类型类型约束?

我没有足够的词汇来表达这个问题(因此,为了寻找答案,如果答案很容易获得,请致歉)。 考虑以下

class RunFoo m where
  runFoo :: m a -> a

class RunFooWrapper m where
  doRunFoo :: (RunFoo n) => n a -> m a

newtype RunFast a = RunFast a

newtype RunSlow a = RunSlow a

fooExample :: (RunFoo m) => m Bool
fooExample = undefined

fooWrapperExample :: (RunFooWrapper m) => m Bool
fooWrapperExample = doRunFoo fooExample

这不会编译: Could not deduce (RunFoo n0) arising from a use of 'doRunFoo'

看起来,编译器(GHC 7.10)坚持从fooExamplem的具体实例化,因此拒绝继续。 但在这种情况下,我不明白为什么该程序是不正确的类型 - fooExample显式定义了一个RunFoo m并且所有doRunFoo要求的是一个RunFoo x 。 那么为什么这不起作用呢?

作为一个补充问题,是否有某种特殊扩展(可能与存在类型有关)可以允许这样的程序? 理想情况下,我希望能够说doRunFoo将任何定义为“ RunFoo m => m (而不是具体实例化RunFoo )的存在性定义为(?)。

动机

我想创建可组合的函数,这些函数在类型类型约束的类型的某些方面进行操作 - 如果需要,我可以提供具体的例子来说明我的意思!

编辑更多动力和替代实施

在一般情况下,我很好奇这个问题的答案,但我想我会补充一点,在这个问题上我碰到了这个问题,我真正想要的是在单子之间进行一种有限的授权。 所以我想写一个monad中的函数,这个函数只能被一个在另一个类中调用monad的类型类所约束。 然后可以在不同的上下文中运行顶层函数,执行相同的逻辑,但根据包装monad将底层实现换出。 由于包装和实现monad之间存在一对一的对应关系,因此我可以使用类型族进行此操作,所以

class (RunFoo (RunFooM m)) => RunFooWrapper m where
  type RunFooM m :: * -> *
  doRunFoo :: RunFooM m a -> m a

instance RunFooWrapper RunFooWrapperSlow where 
  type RunFooM RunFooWrapperSlow = RunSlow
  doRunFoo :: [...]

这意味着fooExample m的解析是由包装monad的类上下文确定的,似乎工作正常,但与haoformayor提供的解决方案相比,它是一个非常狭窄的解决方案。


RankNTypes

{-# language RankNTypes #-}    

class RunFoo m where
  runFoo :: m a -> a

class RunFooWrapper m where
  doRunFoo :: (forall n. RunFoo n => n a) -> m a

fooExample :: RunFoo m => m Bool
fooExample = undefined

fooWrapperExample :: RunFooWrapper m => m Bool
fooWrapperExample = doRunFoo fooExample

(forall n. RunFoo n => na) -> ma是关键区别。 它可以让你传入fooExample ,其类型为forall m. RunFoo m => m Bool forall m. RunFoo m => m Bool (所述forall由编译器被隐含地添加)等的m与结合n和大家乐。 虽然我无法读懂头脑,但我相信这种类型反映了你的真实意图。 你只需要一个RunFoo实例,没有什么更多的了,并且将n作用于第一个参数提供它。

问题是您的代码被隐式输入为forall n. RunFoo n => na -> ma forall n. RunFoo n => na -> ma 。 这意味着你需要首先选择一个n ,使得RunFoo n ,然后拿出一个类型为na的值作为第一个参数传入。 这种简单的移动括号(增加n的等级)的行为完全改变了含义。

对于有同样问题的人的例子,请看这个堆栈溢出问题。 有关RankNTypes的更好解释比我能提供的更详细,请参阅Oliver的博客文章。

链接地址: http://www.djcxy.com/p/1155.html

上一篇: Why can't a function take a type constrained only by a typeclass?

下一篇: Compiling very large constants with GHC