为什么类型参数不能是什么?

时间:2013-11-15 03:14:04

标签: haskell

在我看来,类型参数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 []
[]

2 个答案:

答案 0 :(得分:7)

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

让我们绕道一些术语。 Haskell默认为所谓的“通用量化”。这意味着所有实例化可以满足给定的类型变量。呼叫者可以随意填写它。

所以当你说

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

就像说,“对于每种可能的类型a,将其视为列表”,这显然是无稽之谈!

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

{-# 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

答案 1 :(得分:0)

让我们思考,它可能是写的(它不是,但为了好玩):

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

这意味着通过模式匹配,

fun _ = error "Nonwritten error!"

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

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

data Universe = forall a. a

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

2)这意味着你签名不对:

fun :: Universe -> Universe