简体   繁体   English

Haskell中的部分函数应用

[英]Partial Function Application in Haskell

I'm just starting to learn Haskell from this wikibook and I had a little trouble with one of the exercises. 我刚开始从这个wikibook学习Haskell,我在其中一个练习中遇到了一些麻烦。

Specifically, the following doesn't work as I expect 具体来说,以下内容无法正常工作

parseNumber :: Parser LispVal
parseNumber = (many1 digit) >>= (return $ Number . read)

unless I change it slightly 除非我稍微改变它

parseNumber :: Parser LispVal
parseNumber = (many1 digit) >>= (\n -> return $ Number . read $ n)

I was hoping someone could explain why return $ Number . read 我希望有人可以解释为什么return $ Number . read return $ Number . read doesn't evaluate to the same lambda function that I explicitly created in the second definition, since I thought that this is exactly what partial function evaluation does when it's used in point free style code (obviously not!) return $ Number . read没有计算到我在第二个定义中明确创建的同一个lambda函数,因为我认为这正是部分函数求值在点自由样式代码中使用时的作用(显然不是!)

Thanks for any help, hopefully it's not another beginner's monad problem... 感谢您的帮助,希望这不是另一个初学者的monad问题......

This is just an issue of how $ associates. 这是多么的问题$同伙。 Fundamentally, $ is just an operator for writing fewer parentheses; 从根本上说, $只是一个编写较少括号的运算符; it's the same as adding parentheses wrapping to the end of the expression. 它与将括号括起来添加到表达式的末尾相同。

Using this idea, we can rewrite your second example: 使用这个想法,我们可以重写你的第二个例子:

parseNumber = (many1 digit) >>= (\n -> return (Number . read ( n)))

For reference, the original expression with parentheses looks like this: 作为参考,带括号的原始表达式如下所示:

parseNumber = (many1 digit) >>= (return (Number . read))

So the equivalent of the partial application is actually: 所以部分应用程序的等效实际上是:

parseNumber = (many1 digit) >>= (\n -> (return (Number . read)) n)

Basically, combining multiple $ associates differently than what you expected. 基本上,组合多个$ associates不同于您的预期。

Go to the definitions -- 转到定义 -

($) :: (a -> b) -> a -> b
($) = id

(.) :: (b -> c) -> (a -> b) -> (a -> c)
(.) f g x = f (g x)

Now you have 现在你有了

return $ Number . read = ($) return (Number . read) -- (.) has higher precedence
                       = return (Number . read)

and the monad you're in is the Parser monad, so this is trying to bind a parsed value to a function that returns a parser for another function (many layers of abstraction!) 你所在的monad是Parser monad,所以这是试图将一个解析后的值绑定到一个函数,该函数返回另一个函数的解析器(多层抽象!)

Instead, what you want is 相反,你想要的是

return . Number . read

which is equivalent to what you wrote, as you can see by doing 正如你所做的那样,这相当于你所写的内容

\n -> return $ Number . read $ n = \n -> return . Number . read $ n  -- definition of (.)
                                 = return . Number . read            -- eta reduction

Finally, note that when you see the pattern 最后,请注意当您看到模式时

x >>= return . f

this can always be replaced with 这总是可以替换

fmap f x -- or liftM f x

ie it shows that you're not really using the Monad instance at all, but instead the weaker (and more general) Functor instance. 即它表明你根本没有真正使用Monad实例,而是使用较弱(和更通用)的Functor实例。

It looks like you want: 它看起来像你想要的:

parseNumber = (many1 digit) >>= (return . Number . read)

or alteratively 或者替代地

parseNumber = (many1 digit) `fmap` (Number . read)

Number . read Number . read is a function String -> LispVal so the type of return $ Number . read Number . read是一个函数String -> LispVal所以return $ Number . read的类型return $ Number . read return $ Number . read is Parser (String -> LispVal) , while you need the function to have type String -> Parser LispVal return $ Number . readParser (String -> LispVal) ,而你需要函数有类型String -> Parser LispVal

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM