我是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]
但是为什么呢?
谢谢!
如果以...为例
map :: (a -> b) -> [a] -> [b]
这意味着映射采用2个参数
它返回
您已经在这里看到了模式,但是当我们用'a'和'b'代替时,它将更加清晰]
所以这种类型的定义将是
map :: (String -> Int) -> [String] -> [Int]
所以现在它是一个函数,它接受一个String并返回和Int,以及一个String列表并返回一个Ints列表。
说我们的函数,它接受一个String并返回,并且Int为read
。 read
使用您提供的字符串将其转换为其他字符串。因为我们在这里将其放入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
)都是您想要的。您可以通过这种方式强制编译器或解释器识别该函数-然后可以省略,然后编译器/解释器将找出它们(有时甚至比人们最初想到的更好)。
Haskell中的函数使用一种称为currying的符号。定义类似
类型变量
。这意味着当有一个a
时,它必须是相同的类型。Char
仅表示Char
,a
或b
表示Char
或Bool
或Integer
或其他某种类型。关键是,所有a
都将是同一类型。并且所有b
都是相同的类型。例如,map
以一个函数作为其第一个参数,该函数采用一个a
类型的变量并返回另一个b
类型的变量。然后map
返回一个新函数,该函数接受a
类型的列表。此新函数返回类型为b
的列表。
假设您有一个函数increment
,该函数将1加到一个整数中。 map increment [1,2,3]
最终将返回列表[2,3,4]。