为什么使用lambda而不是模式匹配?

时间:2015-01-02 14:14:37

标签: parsing haskell lambda

我正在观看有关haskell https://www.youtube.com/watch?v=9FGThag0Fqs中解析器的教程。讲座从定义一些非常基本的解析器开始。这些将在以后一起用于创建更复杂的解析器。其中一个基本解析器是 item 。这用于从我们正在解析的字符串中提取字符。

所有解析器都具有以下类型:

type Parser a = String -> [(a, String)]                                         

解析器的定义如下:

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版本更清晰?

3 个答案:

答案 0 :(得分:11)

我相信这来自于写作的常见做法

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时的此样式的实例。

答案 1 :(得分:4)

为什么你应该避免使用等式函数定义(作者:Roman Cheplyaka): http://ro-che.info/articles/2014-05-09-clauses

以上链接的主要观点:

  • DRY:重复函数和参数名称 - >更难以重构
  • 清除程序显示函数决定的参数
  • 易于添加pragma(例如用于分析)
  • 在语法上更接近低级代码

这并不能解释lambda ..

答案 2 :(得分:3)

我认为他们绝对平等。 lambda样式定义将名称item放入匿名lambda函数中,该函数在内部进行模式匹配。模式匹配样式定义直接定义它。但最终两者都是进行模式匹配的函数。我认为这是个人品味的问题。

此外,lambda样式的定义可以被认为是pointfree样式,即一个函数定义而没有明确写下它的参数实际上它不是很自由,因为参数仍然是写的(但在不同的地方),但在这种情况下你不能得到任何东西。

这是另一种可能的定义,介于两者之间:

item :: Parser Char
item inp = case inp of
                [] -> []
                (x:xs) -> [(x, xs)]

它基本上与lambda风格完全相同,但不是免费的。