这适用于ghci
data MyList a = Empty | Cons a (MyList a) deriving (Show, Eq, Read, Ord)
let x = Cons(21, Cons(12, Empty))
但是当我输入时:
Prelude> x
我收到此错误:
No instance for (Show (MyList (Integer, MyList (Integer, MyList a0) ->
MyList (Integer, MyList a0)) ->
MyList (Integer, MyList (Integer, MyList a0) ->
MyList (Integer, MyList a0)))) arising from a use of `print'
答案 0 :(得分:8)
您使用错误的语法进行功能应用。以下代码可以满足您的需求:
let x = Cons 21 (Cons 12 Empty)
原因是Cons
构造函数是一个curried函数,但你将它视为一个未经验证的函数。
考虑以下函数添加两个整数:
add :: Int -> (Int -> Int)
add = \x -> (\y -> x + y)
这里我们说add
是一个函数,它接受x
类型的参数Int
并返回一个函数,
它接受类型y
的参数Int
并返回x + y
类型的Int
。
我们可以将此功能应用为(add 1) 2
评估为3
。
函数应用程序在Haskell中是左关联,这意味着我们不需要括号
在(add 1) 2
中,只需撰写add 1 2
。
函数类型构造函数->
在Haskell中是右关联,这意味着我们不需要add :: Int -> (Int -> Int)
中的括号,只需编写{{ 1}}。
此外,我们不必使用lambdas明确定义add :: Int -> Int -> Int
,并且可以使用以下表示法:
add
将多参数函数编码为单参数函数返回单参数函数在Haskell中非常常见。这种方法具有很好的属性,我们也可以部分应用一个函数。例如,以下函数只需一个add :: Int -> Int -> Int
add x y = x + y
并添加2:
Int
但我们也可以部分应用 add2 :: Int -> Int
add2 x = add 2 x
并简单地写:
add
这也称为无点符号,其中参数称为点。
可以使用元组值来完成多参数函数的替代编码,即
add2 :: Int -> Int
add2 = add 2
我们可以调用此函数,例如add' :: (Int, Int) -> Int
add' (x, y) = x + y
,它构造对add' (2, 3)
并将其作为单个参数传递给(2, 3) :: (Int, Int)
函数。
在标准库中有两个函数可以在两种样式之间转换函数。
add'
例如curry :: ((a, b) -> c) -> a -> b -> c
curry f x y = f (x, y)
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f (x, y) = f x y
为我们提供了curry add'
,add
为我们提供了uncurry add
。
请注意,我们也可以将未经验证的应用程序编写为add'
,它与部分应用程序和多态性一起解释了为什么add'(2, 3)
不会直接导致错误,但ghci随后说出了神秘的东西关于let x = Cons(21, Cons(12, Empty))
的评估。
这里发生的事情是x
是某种类型(12, Empty)
的{{1}}类型对。
然后将该对用作(Int, MyList a)
中的第一个参数,因此我们得到一个部分应用的函数
a
并将Cons (12, Empty)
作为此列表的元素追加。
MyList (Int, MyList a)
同样适用于我们部分应用一对21和前面提到的部分函数。最后,我们告诉ghci打印一个无法显示的函数,因此会抱怨相应函数类型缺少(12, Empty)
实例。