haskell 将类约束添加到类型类示例

c9x0cxw0  于 2022-11-14  发布在  其他
关注(0)|答案(3)|浏览(134)

我尝试实现Cantor Pairing函数,作为一个泛型Pair类型类的示例,如下所示:

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

我如何添加适当的积分约束到示例中?我有一种模糊的感觉,我可能需要修改Pair接口本身,但不知道如何去做。

sgtfey8w

sgtfey8w1#

如果您可以访问类定义,则可以为pikl方法添加一个Integral约束。没有什么可以说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 _ = ()
jmp7cifd

jmp7cifd2#

是否希望所有的对都包含整数元素?在这种情况下,可以将约束添加到方法的签名中:

class Pair p where
  pi :: Integral i => i -> i -> p i
  k :: Integral i => p i -> i
  l :: Integral i => p i -> i

这将使你的pair类不那么通用,但将确保你的CantorPair类型可以是它的一部分。
如果你想让你的Pair类保持一定的通用性,你可以使用一个多参数类型类。(这需要两个扩展:MultiParamTypeClassesFlexibleInstances)。

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

我不知道从设计的Angular 来看,这是否是最好的选择,但这是了解多参数类型类如何工作的好方法。(不可否认,这相当简单。)

72qzrwbm

72qzrwbm3#

这个解决方案使用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

相关问题