如何解决Haskell 是否有隐式模式匹配?
以这个例子为例:
module Main where
main = print (reverseWords "lol")
reverseWords :: String -> [String]
reverseWords = words
reverseWords
函数不与此处的任何参数进行模式匹配,但该函数会运行并输出 "[lol]"
。
我有两个问题:
-
Haskell 如何知道我是否正在针对
words
的输入调用reverseWords
函数?在这种语法中,看起来我只是简单地返回函数words
。 -
为什么即使我没有在模式中向
reverseWords
提供任何输入参数,它也能成功运行?
解决方法
您只是说reverseWords
是函数words
。任何出现 reverseWords
的地方,都可以用函数 words
代替。所以 print (reverseWords "lol")
完全等同于 print (words "lol")
。基本上,你有这个新函数 reverseWords
,它接受一个 String
参数,就像 words
一样,只是将该参数传递给 words
,返回 words
返回的任何内容那个论点。您对 reverseWords
的定义相当于:
reverseWords :: String -> [String]
reverseWords s = words s
综上所述,reverseWords
是一个误导性名称,因为它的作用与 words
没有任何不同。所以,你根本没有做任何有用的事情,只是重命名了一些东西。一个更好的例子是这样的:
reverseWords :: String -> [String]
reverseWords = reverse . words
其中 reverse
是您使用组合运算符 words
与 (.)
组合的其他一些函数,以创建一个可以执行某些有用操作的新函数。这称为无点样式,您可以通过组合其他函数而不引用任何参数来定义新函数。该定义等效于:
reverseWords :: String -> [String]
reverseWords s = reverse (words s)
,
您正在声明一个新函数 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
和 {{1} })。因为函数是一流的,我们可以做同样的事情:
+
这里我们不说 reversedWords :: String -> [String]
reversedWords = reverse . words
等于现有函数,而是计算 reversedWords
是您通过调用组合运算符获得的函数 {{ 1}} 在预先存在的函数 reverseWords
和 .
上。但我们仍在计算函数(reverse
类型),而不是函数的结果(words
类型)。
所以回答你的问题:
haskell 如何知道我是否正在针对 reverseWords 的输入调用“words”函数?在这种语法中,看起来我只是简单地返回函数“words”
是的,您是只是返回函数 String -> [String]
。但是您将它作为 function [String]
本身(在它应用于任何事物之前)“返回”,不是作为结果 words
应用时。这就是 Haskell 如何知道 reversedWords
函数将接收 reversedWords
的输入; words
等于到 reverseWords
,所以任何时候你把一些输入传递给 reverseWords
你实际上是把它传递给 words
。
为什么即使我没有在模式中向 reverseWords 提供任何输入参数,它也能成功运行?
因为您定义了函数 reverseWords
。您通过声明它等于某个其他现有函数来定义它,因此它执行该函数所做的任何事情。为函数结果(基于参数)编写规则并不是定义函数的唯一方法。
您没有在定义中为 words
的参数提供名称这一事实正是 Haskell 知道您在做什么的原因。如果您正在定义类型为 reverseWords
的函数并为参数命名,则右侧必须是类型为 reverseWords
的东西。如果不这样做,则右侧必须是 A -> B
类型的内容。2
但是对于您的磁贴问题:
haskell 是否有隐式模式匹配?
我不知道如何回答这个问题,因为这个讨论根本没有涉及模式匹配。您可以使用模式匹配在 Haskell 中定义函数,但这不是这里发生的事情。
1 好的,在这种情况下,B
非常显式由规则定义,但通常可以使用多个规则使用模式匹配和守卫,并带有辅助 A -> B
定义;函数的实际值是所有规则(以及如何按自上而下的顺序尝试它们的知识)和 reverseWords
子句的一种紧急属性。
2 无论 where
和 where
是什么,这个逻辑都有效。特别是,A
可能是带有更多箭头的东西!这正是具有多个参数的函数在 Haskell 中的工作方式。一个函数,如:
B
可以定义为:
- 编写一个接受两个参数(一个
B
和一个foo :: Int -> String -> (Int,String)
)的规则,右手边的类型为Int
- 编写一个接受一个参数(
String
)的规则,右手边的类型为(Int,String)
- 编写不带参数的直接定义,右侧类型为
Int
图案清晰;每次向规则添加一个参数时,RHS 都会有一个类型,它会再去掉一个箭头(从左侧开始)。
所有 3 个选项都生成一个函数 String -> (Int,String)
,其类型相同,您可以以相同的方式调用。函数的内部定义与外界无关。
reverseWord
确实“返回”了 words
而不调用它,因此 reverseWords s
变为 words s
-- 因为 reverseWords
返回了 words
, call reverseWords s
变成了 call words s
。
这就像在更传统的语法中定义 foo() { bar }
,然后是 foo()(x)
=== bar(x)
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。