为什么使用 lambda 而不是模式匹配?
Why use lambda instead of pattern matching?
我正在 haskell https://www.youtube.com/watch?v=9FGThag0Fqs 观看有关解析器的教程。本讲座从定义一些非常基本的解析器开始。这些将在以后一起使用以创建更复杂的解析器。基本解析器之一是 item。这用于从我们正在解析的字符串中提取一个字符。
所有解析器都具有以下类型:
type Parser a = String -> [(a, String)]
解析器item定义如下:
item :: Parser Char
item = \inp -> case inp of
[] -> []
(x:xs) -> [(x,xs)]
我不太习惯这种语法,所以我觉得很奇怪。我会写的:
item' :: Parser Char
item' [] = []
item' (x:xs) = [(x,xs)]
在ghci中测试发现它们是相等的:
*Main> item ""
[]
*Main> item "abc"
[('a',"bc")]
*Main> item' ""
[]
*Main> item' "abc"
[('a',"bc")]
讲师有一个简短的评论,认为它看起来更清晰,但我不同意。所以我的问题是:
它们真的完全一样吗?
为什么 lambda 版本更清晰?
我认为他们是绝对平等的。 lambda 样式定义将名称 item
放入匿名 lambda 函数,该函数在内部进行模式匹配。 pattern-matching-style 定义直接定义它。但最终两者都是进行模式匹配的函数。我认为这是个人品味问题。
此外,lambda 风格的定义可以被认为是 pointfree 风格,即定义的函数没有明确写下它的参数 实际上它不是很毫无意义,因为论点仍在写(但在不同的地方),但在这种情况下你不会得到任何东西。
这是另一个可能的定义,介于两者之间:
item :: Parser Char
item inp = case inp of
[] -> []
(x:xs) -> [(x, xs)]
它本质上与 lambda 风格相同,但不是 pointfree。
为什么要避免方程式函数定义(作者:Roman Cheplyaka):
http://ro-che.info/articles/2014-05-09-clauses
以上要点link:
- DRY:函数和参数名称重复 --> 更难重构
- 更清楚地显示函数决定哪些参数
- 易于添加 pragma(例如用于分析)
- 语法上更接近低级代码
虽然这并没有解释 lambda..
我相信这来自写作的普遍做法
f :: Type1 -> ... -> Typen -> Result
f x1 ... xn = someResult
我们在类型中恰好有 n
个函数箭头,在等式左侧恰好有 n
个参数。这使得关联类型和形式参数变得容易。
如果Result
是一个函数的类型别名,那么我们可以写成
f :: Type1 -> ... -> Typen -> Result
f x1 ... xn y = something
或
f :: Type1 -> ... -> Typen -> Result
f x1 ... xn = \y -> something
后者遵循上面的约定:n
箭头,n
变量在左侧。此外,在右侧我们有一些 Result
类型的东西,这样更容易发现。前者相反,在快速阅读代码时可能会错过额外的参数。
此外,这种样式可以很容易地将 Result
转换为新类型而不是类型别名:
newtype Result = R (... -> ...)
f :: Type1 -> ... -> Typen -> Result
f x1 ... xn = R $ \y -> something
发布的 item :: Parser Char
代码是 n=0
时此样式的一个实例。
我正在 haskell https://www.youtube.com/watch?v=9FGThag0Fqs 观看有关解析器的教程。本讲座从定义一些非常基本的解析器开始。这些将在以后一起使用以创建更复杂的解析器。基本解析器之一是 item。这用于从我们正在解析的字符串中提取一个字符。
所有解析器都具有以下类型:
type Parser a = String -> [(a, String)]
解析器item定义如下:
item :: Parser Char
item = \inp -> case inp of
[] -> []
(x:xs) -> [(x,xs)]
我不太习惯这种语法,所以我觉得很奇怪。我会写的:
item' :: Parser Char
item' [] = []
item' (x:xs) = [(x,xs)]
在ghci中测试发现它们是相等的:
*Main> item ""
[]
*Main> item "abc"
[('a',"bc")]
*Main> item' ""
[]
*Main> item' "abc"
[('a',"bc")]
讲师有一个简短的评论,认为它看起来更清晰,但我不同意。所以我的问题是:
它们真的完全一样吗? 为什么 lambda 版本更清晰?
我认为他们是绝对平等的。 lambda 样式定义将名称 item
放入匿名 lambda 函数,该函数在内部进行模式匹配。 pattern-matching-style 定义直接定义它。但最终两者都是进行模式匹配的函数。我认为这是个人品味问题。
此外,lambda 风格的定义可以被认为是 pointfree 风格,即定义的函数没有明确写下它的参数 实际上它不是很毫无意义,因为论点仍在写(但在不同的地方),但在这种情况下你不会得到任何东西。
这是另一个可能的定义,介于两者之间:
item :: Parser Char
item inp = case inp of
[] -> []
(x:xs) -> [(x, xs)]
它本质上与 lambda 风格相同,但不是 pointfree。
为什么要避免方程式函数定义(作者:Roman Cheplyaka): http://ro-che.info/articles/2014-05-09-clauses
以上要点link:
- DRY:函数和参数名称重复 --> 更难重构
- 更清楚地显示函数决定哪些参数
- 易于添加 pragma(例如用于分析)
- 语法上更接近低级代码
虽然这并没有解释 lambda..
我相信这来自写作的普遍做法
f :: Type1 -> ... -> Typen -> Result
f x1 ... xn = someResult
我们在类型中恰好有 n
个函数箭头,在等式左侧恰好有 n
个参数。这使得关联类型和形式参数变得容易。
如果Result
是一个函数的类型别名,那么我们可以写成
f :: Type1 -> ... -> Typen -> Result
f x1 ... xn y = something
或
f :: Type1 -> ... -> Typen -> Result
f x1 ... xn = \y -> something
后者遵循上面的约定:n
箭头,n
变量在左侧。此外,在右侧我们有一些 Result
类型的东西,这样更容易发现。前者相反,在快速阅读代码时可能会错过额外的参数。
此外,这种样式可以很容易地将 Result
转换为新类型而不是类型别名:
newtype Result = R (... -> ...)
f :: Type1 -> ... -> Typen -> Result
f x1 ... xn = R $ \y -> something
发布的 item :: Parser Char
代码是 n=0
时此样式的一个实例。