您正在声明一个新函数reverseWords。首先你声明它的类型:
reverseWords :: String -> [String]
所以它将是一个接受字符串并返回字符串列表的函数。
现在有两种方法可以解决这个问题。首先是编写一个规则,说明当reverseWords 接收到某个参数时,结果是一个字符串列表的表达式(可能涉及调用其他函数并使用该参数)。像这样:
reverseWords s = words s
这表示“reverseWords s 形式的表达式被定义为等于words s”。那么编译器就知道reverseWords "lol" 等于words "lol"。函数reverseWords 由我们为其编写的规则隐式定义1。
但是我们可以通过另一种方式来思考这个问题。我假设您对它的工作原理非常满意:
myFavouriteNumber :: Integer
myFavouriteNumber = 28
我们首先声明myFavouriteNumber 的类型为Integer,然后通过写下一个整数来定义它。
嗯,函数是 Haskell 中的第一类值,这意味着我们不必只使用专用的专用语法来定义它们。如果我们可以通过写下一个整数来定义Integer 类型,那么我们应该能够通过写下具有该类型的东西来定义String -> [String] 类型,而不是写下规则。这就是这种形式发生的事情:
reverseWords = words
我们没有为reverseWords 应用于某事物时的结果编写规则,而是写下reverseWords 是什么。在这种情况下,我们告诉编译器reverseWords 被定义为等于words。这仍然让编译器知道reverseWords "lol" 等于words "lol",但它只是通过查看reverseWords 部分来实现;即使不看"lol",它也可以解决这个问题。
此外,我们还可以这样写定义:
two :: Integer
two = 1 + 1
这里不是将two 定义为等于某个预先存在的事物,而是计算它的值(根据其他预先存在的事物:1 和+)。因为函数是一流的,我们可以做同样的事情:
reversedWords :: String -> [String]
reversedWords = reverse . words
这里我们不是说reversedWords 等于现有函数,而是我们计算 reverseWords 是你通过调用组合运算符. 得到的函数- 现有函数reverse 和words。但我们仍在计算函数(类型为String -> [String]),而不是函数的结果(类型为[String])。
所以回答你的问题:
haskell 如何知道我是否针对 reverseWords 的输入调用“words”函数?在这种语法中,看起来我只是在返回函数“words”
是的,您正在只是返回函数words。但是你将它作为 function reversedWords 本身(在它应用于任何东西之前)“返回”它,不是作为 @ 的 result 987654358@ 应用时。这就是 Haskell 知道words 函数是接收reverseWords 的输入的方式; reverseWords等于到words,所以任何时候你将一些输入传递给reverseWords,你实际上是把它传递给words。
为什么即使我没有在模式中向 reverseWords 提供任何输入参数,它也能成功运行?
因为你定义了函数reverseWords。您通过声明它等于某个其他现有函数来定义它,因此它执行该函数所做的任何事情。为函数结果编写规则(基于参数)并不是定义函数的唯一方法。
您没有在定义中为 reverseWords 的参数提供名称这一事实正是 Haskell 知道您在做什么的方式。如果你定义了一个A -> B 类型的函数并且你给参数一个名字,那么右边必须是B 类型的东西。如果你不这样做,那么右手边必须是 A -> B 类型的东西。2
但是对于你的瓷砖问题:
haskell 有隐式模式匹配吗?
我不知道如何回答这个问题,因为这个讨论根本没有涉及到模式匹配。您可以使用模式匹配在 Haskell 中定义函数,但这不是这里发生的事情。
1 好的,在这种情况下,reverseWords 非常明确由规则定义,但通常可以使用多个规则使用模式匹配和守卫来定义函数,并带有辅助where 定义;该函数的实际值是所有规则(以及如何按自上而下的顺序尝试它们的知识)和where 子句的一种涌现属性。
2 无论A 和B 是什么,这个逻辑都有效。特别是,B 可能是带有更多箭头的东西!这正是 Haskell 中具有多个参数的函数的工作方式。像这样的函数:
foo :: Int -> String -> (Int, String)
可以定义为:
- 编写带有两个参数(
Int 和 String)的规则,右侧类型为 (Int, String)
- 编写带有一个参数(
Int)的规则,右侧类型为String -> (Int, String)
- 编写不带参数的直接定义,右侧类型为
Int -> String -> (Int, String)
图案清晰;每次向规则添加参数时,RHS 都会有一个类型会再去掉一个箭头(从左侧开始)。
所有 3 个选项都会生成一个函数 foo,其类型相同,您可以以相同的方式调用。函数的内部定义与外界无关。