3

我(相对)是 Haskell 的新手,想编写一些数学代码。例如,阿贝尔群。我想编写以下代码:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}

module Structures where

class Eq g => AbelianGroup g where
    type family AbelianGroupElement g = e | e -> g
    add :: AbelianGroupElement g -> AbelianGroupElement g -> AbelianGroupElement g
    inv :: AbelianGroupElement g -> AbelianGroupElement g
    unit :: g -> AbelianGroupElement g
    parent :: AbelianGroupElement g -> g

data Z = Z deriving Eq
data ZElement = ZElement Z Int deriving Eq

instance AbelianGroup Z where
    type instance AbelianGroupElement Z = ZElement
    add (ZElement z1 x1) (ZElement z2 x2)
        | z1 == z2 = (ZElement z1 (x1+x2))
        | otherwise = error "elements from different groups"
    inv (ZElement z x) = (ZElement z (-x))
    unit z = ZElement z 0
    parent (ZElement z x) = z

data ProductAbGrp g1 g2 = 
    ProductAbGrp g1 g2 deriving Eq
data ProductAbGrpEl g1 g2 = 
    ProductAbGrpEl (ProductAbGrp g1 g2) (AbelianGroupElement g1) (AbelianGroupElement g2) deriving Eq

编译上面给我的错误

No instance for (Eq (AbelianGroupElement g1))
        arising from the second field of `ProductAbGrpEl'
          (type `AbelianGroupElement g1')

这是有道理的;我没有确保 (AbelianGroupElement g1) 总是为它定义了 Eq。但是,我不确定如何实现这一点。我可以将以上内容更改为

{-# LANGUAGE FlexibleContexts #-} 
...
class (Eq g, Eq (AbelianGroupElement g)) => AbelianGroup g where

但这无济于事。(类型族可能是错误的方式;我最初是从 MultiParamTypeClasses 和 FunctionalDependencies 开始的,但在这方面遇到了其他问题,并得到了类型族更好的印象)。

感谢您阅读本文;任何帮助,将不胜感激。

4

2 回答 2

2

你可以用它StandaloneDeriving来获得你想要的,虽然我承认它不像简单地写那么漂亮deriving Eq

{-# LANGUAGE StandaloneDeriving #-}

deriving instance (Eq g1, Eq g2, Eq (AbelianGroupElement g1), Eq (AbelianGroupElement g2)) => Eq (ProductAbGrpEl g1 g2)
于 2021-04-05T22:51:21.077 回答
0

我最终切换到 MultiParamTypeClasses 和 FunctionalDependencies 方法。我不确定这是否是最好的做事方式,但它至少解决了这个问题。我之前尝试过这个,但不知道我可以同时添加依赖项e -> gg -> e,这在编译这段代码方面有所不同。

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}    

module Structures where
    
class (Eq g, Show g, Eq e, Show e) => AbelianGroup g e | e -> g, g -> e where
    zero :: g -> e
    add :: e -> e -> e
    neg :: e -> e
    parent :: e -> g

data Z = Z deriving (Eq, Show)
data ZElement = ZElement Z Int deriving (Eq, Show)

instance AbelianGroup Z ZElement where
    zero z = ZElement z 0
    add (ZElement z1 x1) (ZElement z2 x2)
        | z1 == z2 = (ZElement z1 (x1+x2))
        | otherwise = error "elements from different groups"
    neg (ZElement z x) = (ZElement z (-x))
    parent (ZElement z x) = z

data ProductAbelianGroup g1 g2 e1 e2 = ProductAbelianGroup g1 g2 deriving (Eq, Show)
data ProductAbelianGroupElement g1 g2 e1 e2 = ProductAbelianGroupElement g1 g2 e1 e2 deriving (Eq, Show)
于 2021-04-09T18:44:38.813 回答