我正在为fraction、vector和matrix算术(即add、sub、穆尔)编写一个类型类,但无法获得vector示例,因为我不知道如何处理函数的递归性质。
代码如下:
class MathObject a where
add :: a -> a -> a
sub :: a -> a -> a
mul :: a -> a -> a
type Vector = [Int]
data Vec = Vec Vector deriving (Show, Eq)
instance MathObject Vec where
add (Vec v1) (Vec v2) = addVecs (Vec v1) (Vec v2)
sub (Vec v1) (Vec v2) = subVecs (Vec v1) (Vec v2)
mul (Vec v1) (Vec v2) = mulVecs (Vec v1) (Vec v2)
addVecs :: Vec -> Vec -> [Int]
addVecs (Vec []) (Vec vec2)= (Vec [])
addVecs (Vec vec) (Vec []) = (Vec [])
addVecs (Vec (x:xs)) (Vec (y:ys)) = e1+e2:rest where
e1 = x
e2 = y
rest = addVecs (Vec xs) (Vec ys)
subVecs :: Vec -> Vec -> [Int]
subVecs (Vec []) (Vec v2) = (Vec [])
subVecs (Vec (x:xs)) (Vec (y:ys)) = x-y:rest where
rest = subVecs (Vec xs) (Vec ys)
mulVecs :: Vec -> Vec -> [Vec]
mulVecs (Vec []) (Vec vec2) = (Vec [])
mulVecs (Vec (x:xs)) (Vec (y:ys)) = e1 * e2:rest where
e1 = x
e2 = y
rest = mulVecs (Vec xs) (Vec ys)
我做了fraction示例,它可以工作,所以我对类型类的工作有一些基本的了解,但是我不知道如何处理递归类型。
1条答案
按热度按时间uurity8g1#
我想说,首先,你已经把自己和太多不同的东西混淆了,这些东西的名字听起来像“vector”。为什么Vec类型有一个名为Vec的构造函数和Vector类型的字段?Vec和Vector之间的区别 * 真的 * 是什么?如果Vector是[Int]的别名,为什么有时你用普通的[Int]来表示向量?你没有包括你得到的编译器错误。但我可以清楚地看到,至少有一些错误是由于这些名称之间的类型不匹配而引起的。
所以首先要做的就是简化它:只有一个Vector类型,它是
newtype
(或者data
,如果您还没有使用newtypes的话) Package 器, Package[Int]
:现在,您始终知道是使用Vector还是[Int],并且可以使用Vector构造函数在两者之间进行转换。
我的下一个观察结果是
addVecs
和friends的类型显然是错误的:为什么它们接受两个Vector
输入并返回一个[Int]
?它们应该坚持使用一个类型,最好是Vector
。这是导致您的一个类型错误的原因:add
必须是a -> a -> a
类型,但是您已经将add
定义为addVecs
,而addVecs
的类型为Vec -> Vec -> [Int]
-这不符合!因此,让我们改为编写现在,这个实现是正确的,因为你选择了一个很差的类型。但是为了使用更好的类型,我们必须在
a+b
周围添加一个Vector
Package 器,然后再将其转化为结果。不过,我不会展示这个实现,因为有一个更好的实现。不要自己做递归,使用Haskell的许多灵活的工具中的一个来处理列表:zipWith
.这与您的实现所做的事情完全相同,但是所有繁琐的 Package 和解 Package 只完成一次,并且
zipWith
完全抽象了递归列表处理。你可以对
subVecs
和mulVecs
做同样的事情,但是你很快就会注意到这里有一些重复。最好把它提取到一个函数中,这样这三个函数就可以共享公共代码:此时,您甚至不需要
addVecs
和friends的定义--您可以轻松地将它们内联到MathObject
示例中: