简体   繁体   English

如何在 Haskell 中的 Functor 和 Applicative 中打印中间结果

[英]how to print intermediate result in Functor and Applicative in Haskell

I am reading the book Programming in Haskell 2nd by Graham Hutton.我正在阅读 Graham Hutton 的《Haskell 2nd 编程》一书。 https://www.cs.nott.ac.uk/~pszgmh/pih.html#slides https://www.cs.nott.ac.uk/~pszgmh/pih.html#slides

When it comes to chapter 13.4 Sequencing parsers, it contains the following functions:说到第 13.4 章排序解析器,它包含以下功能:

> parse three "abcdef" 
[((’a’,’c’),"def")] 
> parse three "ab" 
[]

I would like to understand what are the intermediate steps to evaluate them behind the scene.我想了解在幕后评估它们的中间步骤是什么。 You can find the working source code for the Functor and Applicative for the Parser here:您可以在此处找到用于解析器的 Functor 和 Applicative 的工作源代码:

import Control.Applicative
import Data.Char

-- Basic definitions
newtype Parser a =
  P (String -> [(a, String)])
parse (P p) inp = p inp


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

-- Sequencing parsers
instance Functor Parser
   -- fmap :: (a -> b) -> Parser a -> Parser b
                                               where
  fmap g p =
    P
      (\inp ->
         case parse p inp of
           [] -> []
           [(v, out)] -> [(g v, out)])
--parse  (fmap toUpper item) "abc"

instance Applicative Parser
   -- pure :: a -> Parser a
                            where
  pure v = P (\inp -> [(v, inp)])
   -- <*> :: Parser (a -> b) -> Parser a -> Parser b
  pg <*> px =
    P
      (\inp ->
         case parse pg inp of
           [] -> []
           [(g, out)] -> parse (fmap g px) out)

three :: Parser (Char, Char)
three = pure g <*> item <*> item <*> item
  where
    g x y z = (x, z)

I have attempted it by substituting the definitions from Functor and Applicative in the following way, but dont know how to do it further:我已经尝试通过以下方式替换 Functor 和 Applicative 的定义,但不知道如何进一步做:


parse three "abc"



three :: Parser (Char,Char) 
three 
= pure g <*> item <*> item <*> item 
=P (\inp -> [(g,inp)]) <*> item <*> item <*> item        (apply pure v)

-----------------------------------------------------------------------------------------------------------
=P (
\inp -> case parse P (\inp -> [(g,inp)]) inp of         (apply pg <*> px)
[] -> [] 
[(g,out)] -> parse (fmap g item) out
)

<*> item <*> item 
-----------------------------------------------------------------------------------------------------------
=P (
\inp -> case (\inp -> [(g,inp)]) inp of             (apply parse (P p) inp = p inp
[] -> [] 
[(g,out)] -> parse (fmap g item) out
)

<*> item <*> item 

-----------------------------------------------------------------------------------------------------------
Here, inp=”abc”,  (\inp -> [(g,inp)]),  inp = [  (f x y z =(x,z), “abc”   )]  
=P (
parse (
fmap g item
) out
)                               (apply \inp -> [(g,inp)] on inp)

<*> item <*> item 

It's a good start.这是一个好的开始。 Your last step doesn't look quite right.您的最后一步看起来不太正确。 Stripping off the shared parts, you've written that剥离共享部分,你已经写了

\inp -> case (\inp -> [(g,inp)]) inp of [] -> []; [(g, out)] -> parse (fmap g item) out
=
                                                                parse (fmap g item) out

This equation doesn't look quite right to me: the former is a function, and the latter isn't.这个等式对我来说看起来不太正确:前者是 function,而后者不是。 Additionally, the latter refers to the free variable out , while the former doesn't (because out is bound by the pattern match it's enclosed in).此外,后者指的是自由变量out ,而前者不是(因为out受它所包含的模式匹配的约束)。 A more careful continuation looks like this:更仔细的延续看起来像这样:

\inp -> case (\inp -> [(g,inp)]) inp of [] -> []; [(g, out)] -> parse (fmap g item) out
= { beta reduction, substituting inp for inp }
\inp -> case [(g, inp)]              of [] -> []; [(g, out)] -> parse (fmap g item) out
= { case reduction, substituting g for g and inp for out }
\inp ->                                                         parse (fmap g item) inp

If you like, you could then eta-reduce this to parse (fmap g item) .如果你愿意,你可以 eta-reduce 来parse (fmap g item) Plugging this back into the shared parts we dropped above, we have:将其重新插入我们在上面放置的共享部分,我们有:

three
=
P (parse (fmap g item)) <*> item <*> item

The result can be verified in ghci:结果可以在ghci中验证:

*Parsing> parse three "abc"
[(('a','c'),"")]

*Parsing> let g x y z = (x,z)

*Parsing> parse (P (parse (fmap g item)) <*> item <*> item) "abc"
[(('a','c'),"")]

As next steps, there are three places you could do your next definition-expansion to enable further progress:作为下一步,您可以在三个地方进行下一次定义扩展以实现进一步的进展:

  1. You could expand the fmap in fmap g item .您可以在fmap g item中展开fmap
  2. You could expand the inner (<*>) in P (...) <*> item .您可以扩展P (...) <*> item中的内部(<*>)
  3. You could expand the outer (<*>) in (P (...) <*> item) <*> item .您可以在(P (...) <*> item) <*> item中扩展外部(<*>)

Good luck!祝你好运!

(This is in response to the 'Based on the suggestion of @Daniel Wagner, I expand on fmap gp :' update) (这是对“根据@Daniel Wagner 的建议,我在fmap gp上进行扩展:”更新的回应)

Is the last substitution correct?最后一个替换是否正确?

It's impossible to answer because steps before that are incorrect.无法回答,因为之前的步骤不正确。

There are several problems with your expansion, indicating that you're being sloppy when writing, which has led to mistakes.你的展开有几个问题,说明你写的马虎,导致了错误。 There might also be conceptual problems.也可能存在概念问题。

For example, when you inline three = P... into parse three "abc" , you didn't put parentheses around P... , leading to this line:例如,当您将three = P...内联到parse three "abc"时,您没有在P...周围加上括号,导致这一行:

 parse P (parse (P...)) <*> item <*> item "abc"

This is most likely syntactically incorrect, as it would be parsed like这很可能在语法上不正确,因为它会被解析为

(parse P (parse (P ...))) <*> item <*> (item "abc")

While you likely meant:虽然您可能的意思是:

parse ((P ...) <*> item <*> item) "abc"

If you think, well I'm just doing this to make things easier to write, then check this out: This syntax error also led you to erroneously work on the parse P (parse (P...)) part independently of <*> item <*> item "abc" , which a serious mistake and made most of everything following that irrelevant.如果您认为,我这样做只是为了使事情更容易编写,然后检查一下:此语法错误还导致您错误地处理独立于<*> item <*> item "abc"parse P (parse (P...))部分<*> item <*> item "abc" ,这是一个严重的错误,并使之后的大部分内容都变得无关紧要。

Another thing is this:另一件事是这样的:

 Here, inp="abc", (\inp -> [(g,inp)]), inp = [ (fxyz =(x,z), "abc" )]

This line makes no sense at all.这条线根本没有意义。 Since you are just expanding three , It's not valid to say that inp is anything.由于您只是扩展three ,因此说inp是任何东西都是无效的。 Consider (\x -> x) .考虑(\x -> x) The x here is merely to establish the relationship that the result is the same as the argument, and is not any particular value.这里的x只是为了建立结果与参数相同的关系,而不是任何特定的值。 This is what is meant by it being a bound variable.这就是它是一个绑定变量的意思。

(And I don't even know what you're talking about when you say (\inp -> [(g,inp)]), inp = [ (fxyz =(x,z), "abc" )] . Maybe you can clarify?) (当你说(\inp -> [(g,inp)]), inp = [ (fxyz =(x,z), "abc" )]时,我什至不知道你在说什么。也许你能澄清一下吗?)

This also means that the following makes no sense这也意味着以下没有意义

 (\inp -> case parse item inp of [] -> []; [(v, out)] -> [(gv, out)]))<*> item <*> item “abc” ={substitute inp for "abc"} case parse item "abc" of [] -> []; [(v, out)] -> [(gv, out)]<*> item <*> item

There are multiple problems here.这里有多个问题。 To begin with, the first line has an extra close paren, which makes it hard to see what you mean.首先,第一行有一个额外的近括号,这使得很难理解你的意思。 If we ignore that, then before you had (\inp ->) <*> item... , but afterwards you did not put parens around the case expression, making <*> .如果我们忽略这一点,那么在你有(\inp ->) <*> item...之前,但之后你没有在case表达式周围加上括号,从而制作<*>

Also, it seems that you want to do a beta-reduction here.此外,您似乎想在此处进行 beta-reduction。 A beta reduction always has the form (\v -> E) a , in which the lambda is directly applied to an argument. Beta 缩减始终具有(\v -> E) a形式,其中 lambda 直接应用于参数。 You cannot just say randomly that ' v is equal to a ' and jump around in expressions.你不能随便说 ' v等于a ' 并在表达式中跳来跳去。

For example, If we have f (\x -> x + 1) 3 , is it right to reduce that to f 4 ?例如,如果我们有f (\x -> x + 1) 3 ,将其简化为f 4是否正确? No, because the lambda isn't being applied to 3 .不,因为 lambda 未应用于3

This means that even if the first half is right, the second half of what you wrote is based on a nonsensical step and is irrelevant.这意味着即使前半部分是正确的,你写的后半部分也是基于一个无意义的步骤,是无关紧要的。


I would very much want to tell you how to fix your reduction, but I'm sorry to say that I think what you wrote is beyond repair by now.我非常想告诉你如何修复你的减少,但我很遗憾地说我认为你写的东西现在已经无法修复了。 If you want to have a correct reduction trace, please be more careful with both the syntax and the validity of each step, and do everything again from scratch.如果你想有一个正确的归约轨迹,请更加小心每一步的语法和有效性,并从头开始重新做所有事情。

As an aid, there are several things you should check to see if things went wrong:作为辅助,您应该检查几件事以查看是否出现问题:

  1. Each step should be syntactically valid.每个步骤都应该在语法上有效。 No unbound variables, no missing parens, etc.没有未绑定的变量,没有丢失的括号等。
  2. If the original expression typechecks, then each step must also typecheck and have the same type.如果原始表达式类型检查,那么每个步骤也必须进行类型检查并且具有相同的类型。

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

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