我正在编写一个程序来表示有限群和对其元素的简单操作。我编写了我需要的大部分功能,例如反向元素,生成器,检查子集是否为子组等。
不幸的是我的所有功能都需要标识元素,设置和操作。我想定义类的适当实例并使用它而不是这个三重奏。这里开始我的问题,我不知道如何去做,我在互联网上找到的只包含定义的例子,没有用例。
最后,我想与小组Sn
合作,到目前为止,我已经在(Zn +
)上测试了我的代码。
我写了这个:
data Z2 = Elm Int deriving (Show, Eq)
z2 :: Int -> Z2
z2 a = Elm (a `mod` 2)
class FiniteGroup a where
identity :: a
op :: a -> a -> a -- operation
set :: [a]
instance FiniteGroup Z2 where
identity = (Elm 0)
op (Elm x) (Elm y) = z2 (x+y)
set = [(Elm 0), (Elm 1)]
它适用于函数op
,例如:
*Main> (Elm 1) `op` (Elm 0)
Elm 1
很遗憾,我无法使用identity
和set
。我该如何使用它?
我也无法弄清楚如何重构现有函数以使用我的类型类。
例如我有这个:
cyclicGenerators :: (Eq a) => a -> [a] -> (a -> a -> a) -> [a]
它工作正常,但我希望有这样的东西:
cyclicGenerators :: (Eq a) => FiniteGroup a -> [a]
答案 0 :(得分:2)
我无法使用身份和设置,如何使用它?
您必须在明确定义a
的上下文中使用它们。例如。提供显式类型注释
set :: [Z2]
identity :: Z2
将它们传递给某个需要Z2
的函数也可以。只要编译器能够找出你正在谈论的有限群,你就可以了。否则,你会得到一个模棱两可的......"错误。
如何在功能中替换签名,以及如何在我已经定义的功能中使用身份和设置。
尝试例如。
cyclicGenerators :: (Eq a, FiniteGroup a) => [a]
cyclicGenerators = filter isGenerator set
where isGenerator x = ... -- a Boolean telling whether it's a generator
编译器之上"知道" set
引用有限群a
,因为我们必须返回[a]
而filter
不会更改输入列表的类型,因此{{ 1}}也必须是set
类型。这里类型推断在传播类型时非常有效,因此选择了正确的有限群实例。
编辑:OP提出代码
[a]
会触发歧义错误。实际上,最后一个cyclicGenerators :: (FiniteGroup a) => [a]
cyclicGenerators = filter isGenerator set
where isGenerator = (\x -> groupOrder set == elemOrder x)
并不强制属于同一个组 - 将另一个组的组顺序与set
的顺序进行比较是有意义的。例如。 x
会输入check,因为两者都是整数。
因此,我们需要说明groupOrder (set :: [Z5]) == elemOrder (identity :: [Z2])
的类型是set
。简单的Haskell方式是
[a]
其中 where isGenerator = (\x -> groupOrder (set `asTypeOf` [x]) == elemOrder x)
是一个库函数,它只返回第一个参数,但要求它与第二个参数共享其类型。它在库中定义为:
asTypeOf
或者,我们可以利用GHC Haskell的一个非常常用的扩展。首先,我们需要通过添加
来启用它asTypeOf :: t -> t -> t
asTypeOf x y = x
在模块文件的顶部。然后,我们可以简单地写
{-# LANGUAGE ScopedTypeVariables #-}
我们明确声明cyclicGenerators :: forall a . (FiniteGroup a) => [a]
-- ^^^^^^^^^^ added
cyclicGenerators = filter isGenerator set
where isGenerator = (\x -> groupOrder (set :: [a]) == elemOrder x)
属于set
类型,因此属于同一组。