我正在尝试实现Cantor配对功能,作为一个实例 泛型对类型类,如下:
module Pair (Pair, CantorPair) where
-- Pair interface
class Pair p where
pi :: a -> a -> p a
k :: p a -> a
l :: p a -> a
-- Wrapper for typing
newtype CantorPair a = P { unP :: a }
-- Assume two functions with signatures:
cantorPair :: Integral a => a -> a -> CantorPair a
cantorUnpair :: Integral a => CantorPair a -> (a, a)
-- I need to somehow add an Integral a constraint to this instance,
-- but I can't work out how to do it.
instance Pair CantorPair where
pi = cantorPair
k = fst . cantorUnpair
l = snd . cantorUnpair
如何为实例添加适当的Integral约束? 我有一种模糊的感觉,我可能需要修改Pair接口本身, 但不知道该怎么做。
答案 0 :(得分:2)
如果您有权访问类定义,则可以向Integral
,pi
和k
方法添加l
约束。但这有点令人不满意:没有什么可以说Integral
将成为所有实例的正确约束,而你毕竟不想因为你没有足够的远见而拒绝某些实例。所以,这是一个概括:我们将允许约束在每个实例中变化。
{-# LANGUAGE ConstraintKinds, TypeFamilies #-}
import GHC.Exts
newtype CantorPair a = P { unP :: a }
cantorPair :: Integral a => a -> a -> CantorPair a
cantorUnpair :: Integral a => CantorPair a -> (a, a)
cantorPair = undefined
cantorUnpair = undefined
class Pair p where
type Ctxt p a :: Constraint
pi :: Ctxt p a => a -> a -> p a
k :: Ctxt p a => p a -> a
l :: Ctxt p a => p a -> a
instance Pair CantorPair where
type Ctxt CantorPair a = Integral a
pi = cantorPair
k = fst . cantorUnpair
l = snd . cantorUnpair
-- just for fun
data DataPair a = DataPair a a
instance Pair DataPair where
type Ctxt DataPair a = ()
pi = DataPair
k (DataPair a _) = a
l (DataPair _ a) = a
-- this one made GHC panic! neat, I get to file a bug
data Unit a = Unit
instance Pair Unit where
type Ctxt Unit a = a ~ ()
pi _ _ = Unit
k _ = ()
l _ = ()
答案 1 :(得分:1)
您是否希望所有对总是包含整数元素?在这种情况下,您可以将约束添加到方法的签名中:
class Pair p where
pi :: Integral i => i -> i -> p i
k :: Integral i => p i -> i
l :: Integral i => p i -> i
这会使你的课程不那么通用,但会确保你的CantorPair
类型可以成为其中的一部分。
如果您希望保持Pair
类的一般性,可以使用多参数类型类。 (这需要两个扩展程序:MultiParamTypeClasses
和FlexibleInstances
。)
class Pair p a where
pi :: a -> a -> p a
k :: p a -> a
l :: p a -> a
instance Integral i => Pair CantorPair i where
pi = cantorPair
k = fst . cantorUnpair
l = snd . cantorUnpair
我不知道从设计的角度来看这是否是最好的选择,但这是了解多参数类型类如何工作的好方法。 (诚然,这很简单。)
答案 2 :(得分:1)
此解决方案使用type families,因此您需要-XTypeFamilies
。我们将类型约束放在类型本身上,而不是类型构造函数:
class Pair p where
type First p :: *
type Second p :: *
pi :: First p -> Second p -> p
k :: p -> First p
l :: p -> Second p
然后我们创建像:
这样的实例instance Integral a => Pair (CantorPair a) where
type First (CantorPair a) = a
type Second (CantorPair a) = a
pi = cantorPair
k = fst . cantorUnpair
l = snd . cantorUnpair
instance Pair (a, b) where
type First (a, b) = a
type Second (a, b) = b
pi = (,)
k = fst
l = snd