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