所以我现在正在学习Haskell,我遇到了这个问题:
函数
f
的类型应为a->[a]->a
。该 以下f
的定义不正确,因为它们的类型都是 与a->[a]->a
不同:i. f x xs = xs ii. f x xs = x+1 iii. f x xs = x ++ xs iv. f x (y:ys) = y
我的答案如下:
i) f :: a -> a -> a
这是因为x或xs可以是任何值而不是列表,因为它不包含':'运算符。
ii) f :: Int -> a -> Int
这是因为+运算符在x上使用,意味着x的类型为Int。
iii) f :: Eq a => a -> a -> a
使用++运算符,因此为了连接它们必须是相同的类型..?
iv) f :: a -> [a] -> a
f从列表中返回一个元素。
最后一个肯定是错的,因为它不能是a - > [a] - >一个。还有其他我做错了,为什么?我希望我能完全理解类型以及如何找出函数的类型。
答案 0 :(得分:8)
i) f :: a -> a -> a
f x xs = xs
这是因为x或xs可以是任何值而不是列表,因为它不包含':'操作
是的,但它也不一定是同一类型!
所以,它实际上是f :: a -> b -> b
。
ii) f :: Int -> a -> Int
f x xs = x+1
这是因为+运算符在x上使用,意味着x的类型为Int。
正确。 (实际上,在Haskell中,我们得到Num b => b -> a -> b
,它将Int
概括为任何数字类型,但它并不重要。)
iii) f :: Eq a => a -> a -> a
f x xs = x ++ xs
使用++运算符,因此为了连接它们必须是相同的类型..?
是的,但他们必须是名单。此外,只有在使用Eq
或比较值的内容时才需要==
。
此处f :: [a] -> [a] -> [a]
。
iv) f :: a -> [a] -> a
f x (y:ys) = y
f从列表中返回一个元素。
x
的类型不必相同。我们得到f :: b -> [a] -> a
。
答案 1 :(得分:5)
i. f x xs = xs
(...)
i) f :: a -> a -> a
虽然此 可以是类型签名,但您可以限制性太强。该函数采用两个参数x
和xs
。最初,我们可以推断x
和xs
可以有不同的类型,因此我们说x :: a
和xs :: b
。由于函数返回xs
,因此返回类型也是b
,因此类型为:
f :: a -> b -> b
f x xs = xs
ii. f x xs = x+1
(...)
ii) f :: Int -> a -> Int
您再次使功能限制性太强。让我们再次假设x :: a
和xs :: b
有不同的类型。我们看到我们返回x + 1
(或更多规范形式(+) x 1
。由于(+)
具有签名(+) :: Num c => c -> c -> c
(我们此处使用c
,因为a
已被使用),1
已签名 1 :: Num d => d
,因此我们看到我们使用(+)
和x
来呼叫1
,因此,我们知道a ~ c
(a
和c
属于同一类型)和c ~ d
,因此我们获得了签名:
f :: Num c => c -> b -> c
f x xs = x+1
iii. f x xs = x ++ xs
(...)
iii) f :: Eq a => a -> a -> a
错误:我们在此处看到f
有两个参数,x :: a
和xs :: b
。我们看到我们返回(++) x xs
。由于(++)
具有签名(++) :: [c] -> [c] -> [c]
,因此我们知道a ~ [c]
和b ~ [c]
,因此类型为:
f :: [c] -> [c] -> [c]
f x xs = x ++ xs
iv. f x (y:ys) = y
(...)
iv) f :: a -> [a] -> a
这又是限制性太强。在这里,我们再次看到两个参数:x
和(y:ys)
。我们首先为a
和x :: a
生成(y:ys) :: b
类型,因为第二个参数的模式是(y:ys)
,这是列表构造函数使用参数 (:) :: c -> [c] -> [c]
。因此,我们可以推导出y :: c
和ys :: [c]
,此外模式(y:ys)
的类型为[c]
。由于函数返回y
,我们知道返回类型为c
,因此:
f :: a -> [c] -> c
f x (y:ys) = y
注意:您可以让Haskell派生出函数本身的类型。在GHCi中,您可以使用
:t
命令查询表达式的类型。例如:Prelude> f x (y:ys) = y Prelude> :t f f :: t1 -> [t] -> t