Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Haskell中声明这些函数的类型?_Haskell_Types - Fatal编程技术网

如何在Haskell中声明这些函数的类型?

如何在Haskell中声明这些函数的类型?,haskell,types,Haskell,Types,所以我现在正在学习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 -&g

所以我现在正在学习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]->a。还有其他我做错的吗?为什么?我希望我能完全理解类型以及如何找到函数的类型

i)f::a->a->a

f x xs=xs

这是因为x或xs可以是任何值,并且不是列表,因为它不包含“:”运算符

ii) f :: Int -> a -> Int
没错,但它也不一定是同一类型的! 所以,它实际上是
f::a->b->b

ii)f::Int->a->Int

f x xs=x+1

这是因为+运算符用于x,这意味着x的类型为Int

iii) f :: Eq a => a -> a -> a
对。(实际上,在Haskell中,我们得到了
numb=>b->a->b
,它将
Int
推广到任何数字类型,但这并不重要。)

iii)f::Eq a=>a->a->a

f x xs=x++xs

使用了++运算符,因此为了连接它们,它们必须是相同类型的

iv) f :: a -> [a] -> a
是的,但它们必须是列表。另外,
Eq
仅在使用
==
或比较值的东西时才需要

这里,
f::[a]->[a]->[a]

iv)f::a->[a]->a

fx(y:ys)=y

f从列表中返回一个元素

x
的类型不必相同。我们得到了
f::b->[a]->a

(……)

尽管这可能是一个类型签名,但您将其限制性太强。该函数采用两个参数
x
xs
。最初我们可以推断
x
xs
可以有不同的类型,所以我们说
x::a
xs::b
。由于函数返回
xs
,因此返回类型也是
b
,因此类型为:

f :: a -> b -> b
f x xs = xs
f :: [c] -> [c] -> [c]
f x xs = x ++ xs
(……)

您再次使函数限制性太强。让我们再次假设
x::a
xs::b
具有不同的类型。我们看到我们返回
x+1
(或者以更规范的形式
(+)x1
。因为
(+)
有签名(我们在这里使用
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
(……)

这是错误的:我们在这里看到
f
有两个参数,
x::a
xs::b
。我们看到我们返回
(++)x xs
。因为
(++)
有签名,所以我们知道
a~[c]
b~[c]
,所以类型是:

f :: a -> b -> b
f x xs = xs
f :: [c] -> [c] -> [c]
f x xs = x ++ xs
(……)

这又是限制性太强了。这里我们再次看到两个参数:
x
(y:ys)
。我们首先为
x::a
(y:ys)::b
,因为第二个参数的模式是
(y:ys)
,这是一个带有as参数的列表构造函数
(:)::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

您可以使用
:tf
来获取函数的类型。@WillemVanOnsem我的意思是我想了解如何自己找到类型,以便更好地理解类型
Eq a
并不意味着类型相等。
Eq a
意味着“
a
是一种可以使用
=
检查其值是否相等的类型”。此外,当两个变量具有相同的名称时,它们是相同的,因此,例如,函数
a->a->a
接受两个
a
类型的值(无论最终是什么)并返回另一个值
a
。如果要指示两个参数可以有不同的类型,则需要使用不同的变量。@JamesJohnson手动学习很好,但至少可以使用工具检查答案是否正确。如果不正确,您仍然可以考虑哪里出了问题。我建议先尝试一下ng手动推导它们,然后询问ghci是否正确,然后试图找出错误的地方。您引用的问题不正确(或至少不精确)。如果您给它类型签名
f::a->[a]->a
,实现iv的打字检查就可以了。这不是最通用的类型,但它是(其中之一)它的类型。对于定义
iv
ys:[c]
而不是
ys::c
,我无法编辑它,因为它少于6个字符。@M.Aroosi:正确!感谢您的发现。更新:)
iv) f :: a -> [a] -> a
f :: a -> [c] -> c
f x (y:ys) = y
Prelude> f x (y:ys) = y
Prelude> :t f
f :: t1 -> [t] -> t