鉴于这种:
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
什么,其中的中缀运算符的顺序<$>
,<*>
和<*>
应用?换句话说,如果我以前缀形式重写它:
instance FromJSON Base where
parseJSON (Object v) = Base <$> ((<*>) ((v .: "base123") >>= (.: "key1")) $ (<*>) ((v .: "base123") >>= (.: "key2")) ((v .: "base123") >>= (.: "key3")))
parseJSON _ = mzero
(通知$
运算符),是否会<*>
首先评估第二个元素的右边部分,因为只有在这种情况下才有意义,因为第一个<*>
元素需要2个参数?由于它需要2个参数,因此我们也必须使用$
。
我可能会问我的问题,以致难以理解我的意思,但我希望你确实理解。
实际上您的前缀形式不是很正确,应该是这样的:
parseJSON (Object v) = ((<*>)
((<*>)
((<$>) Base ((v .: "base123") >>= (.: "key1")))
(((v .: "base123") >>= (.: "key2"))))
(((v .: "base123") >>= (.: "key3"))))
上面的定义仍然不是完整的前缀形式。你必须采取>>=
和.:
向左,使他们完全前缀。话虽这么说,要找到以infix形式表示的多个运算符的确切排序顺序,建议您使用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 -> Text -> Text -> Base
λ> :t (Base <$>)
(Base <$>) :: Functor f => f Text -> 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 (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
λ> :t (Base <$> ((v .: "base123") >>= (.: "key1")) <*>)
(Base <$> ((v .: "base123") >>= (.: "key1")) <*>) :: Parser Text -> Parser (Text -> Base)
您可以按照类似的步骤查看如何将其应用于函数定义的其他部分。最后,您将获得的类型Parser Base
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句