Haskell中的类型

问题描述 投票:9回答:4

我是Haskell的新手,我很难理解推断类型和此类如何工作。

map :: (a -> b) -> [a] -> [b]
(.) :: (a -> b) -> (c -> a) -> c -> b

这到底是什么意思?

foldr :: (a -> b -> b) -> b -> [a] -> b
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl1 :: (a -> a -> a) -> [a] -> a

这些之间有什么区别?

和推断的类型

[foldr map[a] -> [a -> a] -> [a]

但是为什么呢?

谢谢!

haskell types type-inference inferred-type
4个回答
10
投票

如果以...为例

map :: (a -> b) -> [a] -> [b]

这意味着映射采用2个参数

  1. 从a型到b型的函数
  2. a型列表

它返回

  1. b的列表

您已经在这里看到了模式,但是当我们用'a'和'b'代替时,它将更加清晰]

  • a =字符串
  • b =整数
  • 所以这种类型的定义将是

map :: (String -> Int) -> [String] -> [Int]

所以现在它是一个函数,它接受一个String并返回和Int,以及一个String列表并返回一个Ints列表。

说我们的函数,它接受一个String并返回,并且Int为readread使用您提供的字符串将其转换为其他字符串。因为我们在这里将其放入Int上下文中,所以它将把字符串转换为int

map read ["1", "2", "112", 333"]

这将导致

[1, 2, 112, 333]

因为map接受了函数read,并且maps

(将其应用于列表的每个元素)。您不必告诉read它是read "1"read n之类的参数,因为map会为您解决这个问题。

而这就是全部。函数的类型仅说明函数采用的类型以及返回的类型。当然,也有一些麻烦,但是您稍后会有意或无意地进行讨论!从根本上讲,该函数不接受many

参数,而仅接受one。,假设您接受了函数+。如果评估1+2,它将返回一个函数,该函数采用另一个已添加到1的数字,并且由于此处存在另一个数字2,它将使用该函数。您可以将其评估为(1+)并继续进行下去,可能稍后再添加该数字。当您没有+的后缀语法时,这会更清楚。它本可以写为(+) 1 2,所以首先该语句变为(+) 1,它是类型(简化的!在这里我不介绍Num类型类)Int -> Int。因此,(+) 1(或该情况下的(1+))只是一个其他函数,您可以向其应用一个值,此时结果将能够计算为3。

[这是实际的外观:(如果让您感到困惑,请忽略此处的(Num a) =>部分,这是一个概念,稍后您将进一步了解。如果需要,只需将此处的a类型替换为Int,然后忽略即可(Num a) =>部分完全。)

 (+)  :: (Num a) => a -> a -> a
 (+2) :: (Num a) => a -> a
(1+)  :: (Num a) => a -> a
(1+2) :: (Num a) => a

Prelude> (+2) 5
7
Prelude> map (+3) [1,2,3]
[4,5,6]

还有第二个问题:根本没有定义推断的类型。之所以将它们称为“推断的”,是因为编译器/解释器本身会“推断”(读取:计算)类型本身,而无需您明确命名它们。

关于foldX差异:它们都做完全相同的事情:将列表缩小为单个值。功能之间的差异仅是内部定义。 foldl从左侧折叠列表,foldr从右侧折叠列表。

因此,总结一个列表,您可以像这样使用所有这些...

foldl1 (+) [1,2,3] == 6
foldr (+) 0 [1,2,3] == 6
foldl (+) 0 [1,2,3] == 6

您看到,除了foldl1之外,您还提供了要折叠的函数,起始值(累加器)和要折叠的列表。 fold1有其自己的累加器,您无需自己提供。

实际上,您最好使用foldr,因为与fold不同,它适用于BIG列表,而不会由于堆栈溢出(tee,hee)而崩溃。并且此规则的例外是foldl'中的Data.Map(请注意“'”!)-这是一个严格的折痕,也适用于大列表。

如果要自己给函数提供类型(如果您编写了函数,请考虑以下示例:

double :: Int -> Int
double n = 2 * n

或以草率的方式

double :: Int -> Int
double = (*2)

两个示例的第一行(double :: Int -> Int)都是您想要的。您可以通过这种方式强制编译器或解释器识别该函数-然后可以省略,然后编译器/解释器将找出它们(有时甚至比人们最初想到的更好)。


3
投票

Haskell中的函数使用一种称为currying的符号。定义类似


1
投票
类型声明中的小写字母是

类型变量

。这意味着当有一个a时,它必须是相同的类型。

1
投票
在Haskell中,小写变量是类型变量。 Char仅表示Charab表示CharBoolInteger或其他某种类型。关键是,所有a都将是同一类型。并且所有b都是相同的类型。

例如,map以一个函数作为其第一个参数,该函数采用一个a类型的变量并返回另一个b类型的变量。然后map返回一个新函数,该函数接受a类型的列表。此新函数返回类型为b的列表。

假设您有一个函数increment,该函数将1加到一个整数中。 map increment [1,2,3]最终将返回列表[2,3,4]。

© www.soinside.com 2019 - 2024. All rights reserved.