2013-11-15 77 views
1

在我看来,类型参数a可以是任何东西,包括一个列表。为什么不能这样工作?为什么不能有一个类型参数是什么?

fun :: a -> a 
fun [] = [] 

Haskell不想编译此代码。我想知道为什么。

Couldn't match expected type `a' with actual type `[t0]' 
`a' is a rigid type variable bound by 
    the type signature for fun :: a -> a 

我可以使它工作改写签名这样

fun :: [a] -> [a] 

但是这不是我期待的,因为我想保持功能多态的东西。 我想知道id如何在空列表上工作。

Prelude> :t id 
id :: a -> a 
Prelude> id [] 
[] 
+0

只接受参数的函数'[]'*不能*是多态!一个允许你的例子进行类型检查的类型系统将是不安全和毫无意义的 - 考虑'好玩3'。 – Fixnum

+0

当'a'是一个列表时,我希望能得到一个'规范'。原来我不允许这样做。 –

+1

我不明白。你的意思是* specialization *吗?如果是这样,你可以编写一个不使用任何参数细节的函数(比如'fun x = x'),或者采用一个额外的参数(可能隐含地通过类型类)来描述如何操作该类型的参数 - 例如'fun ::(a - > a) - > a - > a;有趣的fa = fa' - 一个专门的'$',以及这里唯一的可能性 - 然后你可以调用'[a]'类型的值,比如'fun(\ x-> x ++ x )[3,4,5]'。 – Fixnum

回答

7

类型变量可以是任何东西,但你(被调用者)不要选择什么。

让我们绕开一些术语。 Haskell默认所谓的“通用量化”。这意味着给定的类型变量可以通过全部实例来满足。来电者可以随意填写。

所以,当你说

fun :: forall a. a -> a 
fun [] = [] 

好像是说,“每一个可能的类型a,把它像一个列表”,这显然是无稽之谈!

这听起来像你想要的东西更像是特设多态,我们使用类型类的

{-# LANGUAGE OverlappingInstances, FlexibleInstances #-} 
class Id a where 
    myId :: a -> a 
instance Id a where 
    myId = id 
instance Id [a] where 
    myId [] = [ undefined ] -- special case 
    myId xs = xs 
+0

所以这意味着,只要我声明与某种模式匹配的情况下我松散多态性,不是吗? –

+0

@AlekseyBykov是的,你断言typevariable有一个不起作用的特定类型。如果你想要adhoc多态性,使用类型类 – jozefg

+0

jozefg,所以想法是'a'可以是空的,如果空谓词成立,那么'fun'必须返回'a'。我只想确定我明白你指向的是类型类,我需要声明一个类似MyType类的类,然后为列表创建一个实例:'MyType MyType [a] where isEmpty [] = True',不是吗?如果是这样,那么'fun :: MyType a => a - > a'会起作用,不是吗?但是,如果不匹配[],我将使用'fun a = if isEmpty a then else else'要实现'' –

0

我们认为,这是possibe写的(它不是,而是为了好玩):

fun :: a -> a 
fun [] = [] 

这意味着通过模式匹配,即

fun _ = error "Nonwritten error!" 

这意味着接下来的两件事情:

1)存在额外的数据类型,如:

data Universe = forall a. a 

但这一数据并不存在于哈斯克尔!我们并没有数据构造这里

2)这意味着,你的签名是不正确的:

fun :: Universe -> Universe 
相关问题