类构造函数的语法

时间:2012-09-21 18:39:59

标签: haskell

我有这段代码:

data SafeValue a = SafeValue a a a deriving Eq

class Safe a where
  check::a->Bool
  (+++)::a->a->a

instance (Num a, Eq a) => Safe (SafeValue a) where
  check (SafeValue x y z) | x == y = True
                          | x == z = True
                          | y == z = True
                          | otherwise = False
  (SafeValue a b c)+++(SafeValue x y z) = let new_val = SafeValue (a+x) (b+y) (c+z)
                                          in if check new_val then new_val
                                                              else error "Error"

我想向class Safe添加一个函数,例如:

make_new 3 --> SafeValue 3 3 3

我不知道如何添加它,因为这应该是:

make_new::b->a

但在istance声明中ghci声称它不确定b是什么。

有人可以帮忙吗?

1 个答案:

答案 0 :(得分:5)

核心问题是,您承诺make_new适用于所有类型b,以生成a的值。但是,考虑到SafeValue a的工作方式,这没有意义:给定某种类型a,您会得到SafeValue a。所以你真正想要的是make_new获取某种类型a的值但是给你一个SafeValue a的值。更一般地说,您希望结果属于某种类型s a,其中s是您为其编写实例的实际类型,而a可以是任何类型。

您需要做的是让类接受“更高级”类型的值。 (这意味着类应该期望像SafeValue这样的类型需要另外一个参数。你可以这样做:

class Safe s where
  check :: s a -> Bool
  (+++) :: s a -> s a -> s a
  make_new :: a ->  s a

然后您的实例将如下所示:

instance Safe SafeValue where ...

请注意重要的区别:不是为SafeValue a创建实例,而是在没有类型参数的情况下使用SafeValue

但是,这还有另一个问题:现在您不能将a限制为NumEq的一部分!

您可以使用称为多参数类型类的扩展来解决此问题。所以你的最终版本将是:

class Safe s a where
  check :: s a -> Bool
  (+++) :: s a -> s a -> s a
  make_new :: a -> s a

,您的实例将是:

instance (Num a, Eq a) => Safe SafeValue a where ...

要完成所有这些工作,您需要启用两个扩展程序:

{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}

第一个允许您以更多方式编写实例。通常,您只能为类似T a b c的类型编写实例,其中T是类型,a b c是类型变量;通过此扩展,限制被解除,您可以编写类似我所展示的实例。

多参数类型类扩展允许作用于多种类型的类型类。这使您可以创建一个取决于s a的课程。

最后一点:完全使用类型类可能不是你的例子的正确选择。您是否计划为Safe课程编写更多类型?如果你不是,那么你根本不应该使用类型类。但是,学习一下多参数类型类仍然很有用,所以你应该考虑在某些时候使用它们。