2010-02-22 39 views
11

代码的这个特定部分的目的是使size函数比简单计算elems中的所有元素更有效。我已经解决了总结构成列表的两种类型,但我似乎无法创建大小函数的签名。如何匹配类型“任一b”?

instance (Finite a, Finite b) => Finite (Either a b) where 
    elems = combineLists [Left x | x <- elems] [Right x | x <-elems] 
    size ??? = (size a) + (size b) 

从前奏,我们知道Either a b = Left a | Right b

我尝试的第一件事是匹配Either,但它当然是一种类型,所以这是行不通的。接下来,我试过((Left a) | (Right b)),但是没有继续。没有其他东西似乎与Either a b类型匹配。

我能得到size (Left a)编译,但由于它缺少b成分,我收到错误:

Ambiguous type variable `b' in the constraint: 
    `Finite b' arising from a use of `size' at <interactive>:1:0-12 

这当然是有道理的背景下,但我真的不知道如何匹配Either a b

有人有什么想法吗?

+1

您似乎对类型和构造函数之间的区别有点困惑。 “一个b”是一个带有两个构造函数的类型,“左”和“右”。类型进入类型签名,而构造函数进入代码。这是一个常见的混淆,因为很多类型使用相同的名称作为类型和构造函数,如“data Foo = Foo Int String”;第一个“Foo”是类型,而第二个是构造函数。 – 2010-02-25 20:17:03

回答

25

Either a b类型的东西要么是Left a或​​,所以你有两种情况可以分别进行处理:

size (Left x) = size x 
size (Right x) = size x 

关于暧昧类型变量的错误是另外一个问题。 如果您只是在解释器中输入类似size (Left 1)的东西,则系统无法推断出该值的“正确”类型。它可以是Either Int anything,只要不知道anything是什么类型,则不能检查它是否在Finite(这是size所要求的)类中。

您可以通过指定一个明确的类型签名避免这样的问题:

size (Left 1 :: Either Int String) 
0

麻烦似乎是,你需要为size伪参数,但你不能传递假人两种类型ab在一个单一的Either a b。也许你可以使用elems获得每种类型的虚拟:

size _ = (size . head) (elems :: [a]) + (size . head) (elems :: [b]) 
0

我以为你是核心问题是要表示相互两种类型的在同一时间一个数据类型。 Either a b只能在给定时间为ab之一。

同时代表ab的简单数据类型是2元组。这样的事情的类型签名是(a, b),这也是创建一个表达式,因此模式MACHING之一:

> :type (4,5) 
(4,5) :: (Num t, Num t1) => (t, t1) 
> let f (a, b) = 2*a + b 
> f (4,5) 
13 

你应该考虑用2元组写你的第一线,像这样:

instance (Finite a, Finite b) => Finite (a, b) where 

这是什么Finite (a, b)代表什么?成员函数定义是什么?

+0

其实我已经写过这个定义,它是a和b的产物,创建了所有a到b的映射 – Fry 2010-02-22 17:03:02