[英]Order of evaluation for multiple operators in infix form
鑒於這種:
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
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.