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

时间:2018-04-26 09:49:29

标签: 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 -> a -> Int

这是因为+运算符在x上使用,意味着x的类型为Int。

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

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

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

f从列表中返回一个元素。

最后一个肯定是错的,因为它不能是a - > [a] - >一个。还有其他我做错了,为什么?我希望我能完全理解类型以及如何找出函数的类型。

2 个答案:

答案 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

虽然此 可以是类型签名,但您可以限制性太强。该函数采用两个参数xxs。最初,我们可以推断xxs可以有不同的类型,因此我们说x :: axs :: b。由于函数返回xs,因此返回类型也是b,因此类型为:

f :: a -> b -> b
f x xs = xs
ii. f x xs = x+1
     

(...)

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

您再次使功能限制性太强。让我们再次假设x :: axs :: b有不同的类型。我们看到我们返回x + 1(或更多规范形式(+) x 1。由于(+)具有签名(+) :: Num c => c -> c -> c(我们此处使用c,因为a已被使用),1已签名 1 :: Num d => d ,因此我们看到我们使用(+)x来呼叫1,因此,我们知道a ~ cac属于同一类型)和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 :: axs :: 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)。我们首先为ax :: a生成(y:ys) :: b类型,因为第二个参数的模式是(y:ys),这是列表构造函数使用参数 (:) :: c -> [c] -> [c] 。因此,我们可以推导出y :: cys :: [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