2012-10-03 56 views
7

我有些做作类型:多态约束

{-# LANGUAGE DeriveFunctor #-} 

data T a = T a deriving (Functor) 

...这类型是一些人为的类的实例:

class C t where 
    toInt :: t -> Int 

instance C (T a) where 
    toInt _ = 0 

我怎样才能表达函数约束T a是所有a的某个类的实例?

例如,请考虑以下功能:

f t = toInt $ fmap Left t 

直觉上,我希望,因为toInt作品上T a所有a上述功能的工作,但我无法表达,在类型。这不起作用:

f :: (Functor t, C (t a)) => t a -> Int 

...因为当我们应用fmap类型已经成为Either a b。用我不能修复此:

f :: (Functor t, C (t (Either a b))) => t a -> Int 

...因为b并不代表普遍量化的变量。我也可以说:

f :: (Functor t, C (t x)) => t a -> Int 

...或使用forall x表明约束是适用于所有x

所以我的问题是,如果有一种方式来说约束是多态的一些类型的变量。

+0

我认为像'C类T,其中toInt :: TA - > Int'将无法正常工作,你需要'C'是那种'* - >约束?种友多态会帮助吗? –

+0

@ C.A.McCann我想到的具体类型构造函数是来自'pipes'的'Proxy',具体类是'Monad'。我为类似代理类型的类型分类实用程序函数,这就是为什么约束在那里。遵循你的建议,我会定义一个专门用于'Proxy'类型构造函数形式的'MonadP'类,并将其用作约束。缺点是,如果用户想要编写类似代理类型的代理实用程序函数多态,他们必须重新绑定符号才能使用“MonadP”。 –

+2

你不能直接做,但可以模拟,就像罗马的答案一样。这里是相关的GHC票:http://hackage.haskell.org/trac/ghc/ticket/2893 – glaebhoerl

回答

6

使用constraints包:

{-# LANGUAGE FlexibleContexts, ConstraintKinds, DeriveFunctor, TypeOperators #-} 

import Data.Constraint 
import Data.Constraint.Forall 

data T a = T a deriving (Functor) 

class C t where 
    toInt :: t -> Int 

instance C (T a) where 
    toInt _ = 0 

f :: ForallF C T => T a -> Int 
f t = (toInt $ fmap Left t) \\ (instF :: ForallF C T :- C (T (Either a b))) 
+3

它也值得看看'ForallF'的来源,如果只是为了欣赏背后的想法是多么简单/丑陋/恐怖它是:) – copumpkin

+0

@copumpkin:我其实有一个问题 - http://stackoverflow.com/questions/12728159/how-does-the-constraints-package-work –