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 []
[]
4

2 回答 2

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
于 2013-11-15T03:20:56.283 回答
0

让我们想想,写是可能的(不是,而是为了好玩):

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

这意味着通过模式匹配,

fun _ = error "Nonwritten error!"

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

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

data Universe = forall a. a

但是这些数据在 Haskell 中不存在!而且我们这里没有数据构造函数

2)这意味着您的签名不正确:

fun :: Universe -> Universe
于 2013-11-15T22:59:52.890 回答