以中缀形式对多个操作员进行评估的顺序 [英] Order of evaluation for multiple operators in infix form

查看:70
本文介绍了以中缀形式对多个操作员进行评估的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



  data Base = Base {
key1 :: Text,
key2: :Text,
key3 :: Text
}派生(显示)

实例FromJSON Base其中
parseJSON(Object v)= Base< $> ((v。:base123)>> =(。:key1))*< ((v。:base123)>> =(。:key2))* 1。 - 2
((v。:base123)>> =(。:key3)) - 3

parseJSON _ = mzero

中缀运算符< $> < /> < /> 是否被应用?换句话说,如果我以前缀形式重写它:

  instance FromJSON Base其中
parseJSON(Object v)=基础< $> ((*))((v:base123)>> =(。:key1))$(*)((v:base123)>> ; =(.:key2))((v。:base123)>> =(。:key3)))

parseJSON _ = mzero

(请注意 $ 运算符),第二个的右边部分首先评估< /> ,因为只有在这种情况下,它才有意义,因为第一个 <*> 需要2个参数?而且由于它需要2个参数,所以我们还必须使用 $



我可能会问我的问题我很难理解我的意思,但我希望你明白了。

解决方案

实际上,您的前缀表单并不完全正确,它应该是这样的:
$ b $(< b>
((*)
((< $> $> b> ;)Base((v。:base123)>> =(。:key1)))
(((v。:base123)>> =(。:key2 ))))
(((v。:base123)>> =(。:key3))))

上述定义仍然不是完整的前缀形式。您必须将>> = 。:放在左边,才能使它们成为完全前缀。这就是说,为了找到中缀形式的多个操作符的确切顺序,我建议你使用ghci来获得对类型的更多见解。作为初始步骤,检查所有操作符的关联性和优先顺序:

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

因此,它们都是相关的并具有相同的优先级。定义的中缀形式非常清楚评估的进行方式:它们从左开始,最初< $> 应用于 Base >,然后应用两个< /> 函数。类型 Base 最初应用于< $>

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

现在, (v:base123)>> =(。:key1))应用于上述类型的结果:

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

你可以看到它返回一个封装在 Parser 类型中的函数。要从 Parser 类型中提取底层函数,您必须使用<>



 λ> :t(*)
(*)::适用的f => f(a - > b) - > f a - > f b
λ> :(Base< $>((v。:base123)> =(。:key1))*)
(Base< v:base123)>> =(。:key1))*)::解析器文本 - > Parser(Text - > Base)

您可以按照相似的步骤查看它是如何应用于函数定义的其他部分。最后,您将得到 Parser Base 类型。

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? And since it requires 2 arguments, we have to use $ also.

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. 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. The type Base is initially applied to <$>:

λ> :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:

λ> 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. And to extract the underlying function out of the Parser type, you have to use <*>:

λ> :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.

这篇关于以中缀形式对多个操作员进行评估的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆