[英]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 . read
是Parser (String -> LispVal)
,而你需要函数有类型String -> Parser LispVal
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.