简体   繁体   English

多个运算符的评估顺序以中缀形式

[英]Order of evaluation for multiple operators in infix form

Given this: 鉴于这种:

 data Base = Base {
   key1 :: Text,
   key2 :: Text,
   key3 :: Text
 } deriving (Show)

instance FromJSON Base where
  parseJSON (Object v) = Base <$>
                         ((v .: "base123") >>= (.: "key1")) <*>  -- 1
                         ((v .: "base123") >>= (.: "key2")) <*>  -- 2
                         ((v .: "base123") >>= (.: "key3"))      -- 3

  parseJSON _ = mzero

What's the order of in which the infix operators <$> , <*> and <*> are applied? 前缀运算符<$><*><*>的应用顺序是什么? In other words, if I rewrite it in prefix form: 换句话说,如果我以前缀形式重写它:

instance FromJSON Base where
      parseJSON (Object v) = Base <$> ((<*>) ((v .: "base123") >>= (.: "key1")) $ (<*>) ((v .: "base123") >>= (.: "key2")) ((v .: "base123") >>= (.: "key3")))

      parseJSON _ = mzero

(notice $ operator), will the right part of the second <*> be evaluated first because only in this case it makes sense because the first <*> requires 2 arguments? (注意$运算符),将首先评估第二个<*>的右侧部分,因为仅在这种情况下才有意义,因为第一个<*>需要2个参数? And since it requires 2 arguments, we have to use $ also. 并且由于它需要2个参数,因此我们也必须使用$

I might've asked my question so that it was difficult to understand what I meant but I hope you did understand. 我可能会问我的问题,以致难以理解我的意思,但我希望你确实理解。

Actually your prefix form is not quite correct, it should be like this: 实际上您的前缀形式不是很正确,应该是这样的:

parseJSON (Object v) = ((<*>)
                        ((<*>)
                         ((<$>) Base ((v .: "base123") >>= (.: "key1")))
                         (((v .: "base123") >>= (.: "key2"))))
                        (((v .: "base123") >>= (.: "key3"))))

The above definition is still not in complete prefix form. 上面的定义仍然不是完整的前缀形式。 You have to take >>= and .: to the left to make them completely prefix. 您必须在左边加上>>=.:使其完全前缀。 That being said, to find the exact order of evaluation of multiple operators in infix form I would suggest you to play up in ghci to get more insights into types. 话虽这么说,要找到以infix形式表示的多个运算符的确切评估顺序,建议您使用ghci进行操作,以获取更多有关类型的见解。 As an initial step, check the associativity and the precedence order for all the operators: 首先,请检查所有运算符的关联性和优先顺序:

λ> :i (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
infixl 4 <$>
λ> :i (<*>)
(<*>) :: f (a -> b) -> f a -> f b
infixl 4 <*>

So, they both are left associative and have the same precedence. 因此,它们都保持关联并且具有相同的优先级。 The infix form of the definition is quite clear on how the evaluation will take place: they start from left and initially <$> is applied over Base and then followed by application of two <*> functions. 定义的中缀形式非常清楚如何进行评估:它们从左开始,首先在Base上应用<$> ,然后再应用两个<*>函数。 The type Base is initially applied to <$> : 类型Base最初应用于<$>

λ> :t Base
Base :: Text -> Text -> Text -> Base
λ> :t (Base <$>)
(Base <$>) :: Functor f => f Text -> f (Text -> Text -> Base)

Now, ((v .: "base123") >>= (.: "key1")) is applied to the resultant of the above type: 现在,将((v .: "base123") >>= (.: "key1"))应用于上述类型的结果:

λ> let (Object v) = undefined :: Value
λ> :t (Base <$> ((v .: "base123") >>= (.: "key1")))
(Base <$> ((v .: "base123") >>= (.: "key1"))) :: Parser (Text -> Text -> Base)

You can see that it returns a function wrapped in Parser type. 您会看到它返回包装在Parser类型中的函数。 And to extract the underlying function out of the Parser type, you have to use <*> : Parser类型中提取基础函数,必须使用<*>

λ> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
λ> :t (Base <$> ((v .: "base123") >>= (.: "key1")) <*>)
(Base <$> ((v .: "base123") >>= (.: "key1")) <*>) :: Parser Text -> Parser (Text -> Base)

You can follow the similar steps to see how it is applied to the other parts of the function definition. 您可以按照类似的步骤查看如何将其应用于函数定义的其他部分。 At the end, you will get a type of Parser Base . 最后,您将获得一种Parser Base

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

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