2013-06-22 48 views
6

当我有像在Haskell以下数据类型:约束种:通过多个约束

data A ctx = A (forall a. ctx a => a -> a) 

然后,我可以把那类型的给定类的工作价值这一数据类型的功能:

> A (+3) :: A Num 
A (+3) :: A Num :: A Num 

但是,是否可以将具有多个约束的函数放入此数据类型?我试过这个:

> :t ((+ 3) . succ) 
((+ 3) . succ) :: (Enum c, Num c) => c -> c 
> :t A ((+ 3) . succ) :: A (Enum,Num) 
    Expecting one more argument to `Enum' 
    In an expression type signature: A (Enum, Num) 
    In the expression: A ((+ 3) . succ) :: A (Enum, Num) 

所以这是行不通的。怎么可能做我想做的事,或者不可能?我知道一种解决方案是使用“虚拟”数据类型和类型族,但如果因为复杂性而有其他方式,我不想那样做。此外,我可以使用这个例子(+1)而不是succ,但是在更复杂的情况下,只能对一个类进行转换是不可能的。

+0

什么样'类(民一,枚举一)=>富了'另一类型类的? – thoferon

+0

是的,那当然也有效,但我并不喜欢仅仅为了结合两个上下文而创建一个类型类 – bennofs

回答

1

我发现了一种将多个类连接成一个概念的概念。尽管使用起来很尴尬,但它起作用。

{-# LANGUAGE ConstraintKinds  #-} 
{-# LANGUAGE EmptyDataDecls  #-} 
{-# LANGUAGE FlexibleContexts  #-} 
{-# LANGUAGE FlexibleInstances  #-} 
{-# LANGUAGE GADTs     #-} 
{-# LANGUAGE KindSignatures  #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE OverlappingInstances #-} 
{-# LANGUAGE RankNTypes   #-} 
{-# LANGUAGE ScopedTypeVariables #-} 
{-# LANGUAGE TypeOperators   #-} 
{-# LANGUAGE UndecidableInstances #-} 
module Test where 

import GHC.Exts 

data (:>+<:) ctx1 ctx2 a where 
    C'C :: (ctx1 a, ctx2 a) => (ctx1 :>+<: ctx2) a 

data (:++:) (ctx1 :: * -> Constraint) (ctx2 :: * -> Constraint) = C 

class Ctx2 c1 c2 a where 
    useCtx :: c1 :++: c2 -> a -> ((c1 :>+<: c2) a -> b) -> b 

instance (c1 a, c2 a) => Ctx2 c1 c2 a where 
    useCtx _ a f = f C'C 

fC :: (Ctx2 Num Enum a) => a -> a 
fC a = useCtx (C :: Num :++: Enum) a $ \C'C -> 3 + succ a 

data A ctx = A 
    { call :: forall a. ctx a => a -> a 
    } 

main = print $ call (A fC :: A (Ctx2 Num Enum)) 3 

应该可以使用约束别名来定义Ctx3,Ctx4,...