Haskell 使用类中定义的函数
我正在写一个程序来表示有限群和对其元素的简单运算。我编写了我需要的大部分功能,例如逆元素、生成器、检查子集是否为子组等 不幸的是,我所有的函数都需要标识元素、集合和操作。我想定义类的适当实例,并使用它来代替这个三元组。我的问题就从这里开始,我不太知道该怎么做,我在互联网上能找到的只有定义的例子,没有用法的例子 最后,我想与组Haskell 使用类中定义的函数,haskell,functional-programming,finite-group-theory,Haskell,Functional Programming,Finite Group Theory,我正在写一个程序来表示有限群和对其元素的简单运算。我编写了我需要的大部分功能,例如逆元素、生成器、检查子集是否为子组等 不幸的是,我所有的函数都需要标识元素、集合和操作。我想定义类的适当实例,并使用它来代替这个三元组。我的问题就从这里开始,我不太知道该怎么做,我在互联网上能找到的只有定义的例子,没有用法的例子 最后,我想与组Sn,到目前为止,我已经在(Zn+)上测试了我的代码 我写道: data Z2 = Elm Int deriving (Show, Eq) z2 :: Int -> Z
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]
我不能使用身份和设置,如何使用它
您必须在明确定义a
的上下文中使用它们。例如,提供显式类型注释
set :: [Z2]
identity :: Z2
将它们传递给需要Z2
的函数也可以。只要编译器能找出你所说的是哪一个有限群,你就没事了。否则,将出现“不明确…”错误
如何在函数中替换签名,以及如何在我已经定义的函数中使用identity和set
试试看
cyclicGenerators :: (Eq a, FiniteGroup a) => [a]
cyclicGenerators = filter isGenerator set
where isGenerator x = ... -- a Boolean telling whether it's a generator
上面,编译器“知道”集合指的是有限群a
,因为我们必须返回[a]
,并且过滤器
不会改变输入列表的类型,因此集合也必须是[a]
类型。在这里,类型推断在传播类型时非常有效,因此可以选择正确的有限群实例
编辑:OP提出代码
cyclicGenerators :: (FiniteGroup a) => [a]
cyclicGenerators = filter isGenerator set
where isGenerator = (\x -> groupOrder set == elemOrder x)
这会引发歧义错误。事实上,最后一个集合
并不强制属于同一组——将另一组的组顺序与x
的顺序进行比较是有意义的。例如,groupOrder(set:[Z5])==elemOrder(identity:[Z2])
将进行类型检查,因为两者都是整数
所以我们需要声明集合的类型是[a]
。简单的哈斯克尔方法是
where isGenerator = (\x -> groupOrder (set `asTypeOf` [x]) == elemOrder x)
其中,asTypeOf
是一个库函数,它只返回其第一个参数,但要求它与第二个参数共享其类型。在库中定义为:
asTypeOf :: t -> t -> t
asTypeOf x y = x
或者,我们可以利用GHC Haskell的一个非常常用的扩展。首先,我们需要通过添加
{-# LANGUAGE ScopedTypeVariables #-}
在模块文件的顶部。然后,我们可以简单地写
cyclicGenerators :: forall a . (FiniteGroup a) => [a]
-- ^^^^^^^^^^ added
cyclicGenerators = filter isGenerator set
where isGenerator = (\x -> groupOrder (set :: [a]) == elemOrder x)
我们明确指出,set
属于[a]
类型,因此它属于同一个组。我写了这样的话:得到了:谢谢,你帮了我很多忙!有没有一个地方可以让我更多地了解类似的问题?你能告诉我“全部a”是什么意思吗?基本上,全部a的通用量词
表示调用方可以选择a
作为它想要的内容。请注意,在这种特殊情况下,省略所有a的。
不会更改类型:调用方无论如何都可以选择a
。然而,GHC处理这个多余的量词的意思是“注意调用方选择的a
——如果下面我再次使用a
,我指的是这样选择的类型,因为你可以阅读到血淋淋的细节