Haskell 中的 ApplicativeDo pragma 和 Applicative Functor
ApplicativeDo pragma and Applicative Functor in Haskell
来自 Functor、Applicative 和 Monad 的示例
略有改动:
{-# LANGUAGE ApplicativeDo #-}
import Safe (readMay)
-- import Control.Applicative ((<$>), (<*>))
displayAge maybeAge =
case maybeAge of
Nothing -> putStrLn "You provided invalid input"
Just age -> putStrLn $ "In that year, you will be: " ++ show age
yearDiff futureYear birthYear = futureYear - birthYear
maybeAge fS bS = do
fI <- readMay fS
bI <- readMay bS
pure $ yearDiff fI bI
main = do
putStrLn "Please enter your birth year"
birthYearString <- getLine
putStrLn "Please enter some year in the future"
futureYearString <- getLine
displayAge $ maybeAge birthYearString futureYearString
其中 maybeAge
和 do
我用而不是
maybeAge fS bS = yearDiff <$> readMay fS <*> readMay bS
我有 2 个问题:
- 如何检查
maybeAge
在这种情况下使用 Applicative Functor 语义还是 Monad 语义?
- 如果使用 Applicative Functor,在这种情况下有什么优势?
关于:ApplicativeDo.
我用你的例子做了一个独立的例子:
{-# LANGUAGE ApplicativeDo #-}
import Text.Read (readMaybe)
displayAge :: Maybe Int -> IO ()
displayAge maybeAge =
case maybeAge of
Nothing -> putStrLn "You provided invalid input"
Just age -> putStrLn $ "In that year, you will be: " ++ show age
yearDiff :: Int -> Int -> Int
yearDiff = (-)
maybeAge :: String -> String -> Maybe Int
maybeAge fS bS = do
fI <- readMaybe fS
bI <- readMaybe bS
pure $ yearDiff fI bI
main :: IO ()
main = do
putStrLn "Please enter your birth year"
birthYearString <- getLine
putStrLn "Please enter some year in the future"
futureYearString <- getLine
displayAge $ maybeAge futureYearString birthYearString
此外,在最后一行中,我交换了参数,因为它们在您的示例中的顺序似乎有误。我还根据@Redu 的评论改进了 yearDif
定义。
这里是您问题的答案。
您可以按照 GHC User Guide 中的建议检查是否确实应用了应用(和仿函数)操作,即使用 -ddump-ds
编译器开关。我在下面添加了几个开关以使输出更简洁。我也只展示了关于 maybeAge
函数的摘录。
$ ghc appdo.hs -ddump-ds -dsuppress-type-applications -dsuppress-module-prefixes
[1 of 1] Compiling Main ( appdo.hs, appdo.o )
==================== Desugar (after optimization) ====================
Result size of Desugar (after optimization)
= {terms: 75, types: 75, coercions: 0, joins: 0/0}
...
-- RHS size: {terms: 17, types: 13, coercions: 0, joins: 0/0}
maybeAge :: String -> String -> Maybe Int
[LclId]
maybeAge
= \ (fS_a1h3 :: String) (bS_a1h4 :: String) ->
<*>
$fApplicativeMaybe
(fmap
$fFunctorMaybe
(\ (fI_a1h5 :: Int) (bI_a1h6 :: Int) -> yearDiff fI_a1h5 bI_a1h6)
(readMaybe $fReadInt fS_a1h3))
(readMaybe $fReadInt bS_a1h4)
...
当然,这里没有加速。 Maybe
的应用运算具有恒定的复杂性(O(1)
)——就像单子运算一样。
在 original paper 中,ApplicativeDo
的作者给出了几个更复杂的 monadic 类型的例子(Haxl
、Data.Seq
、解析等),允许渐近地更高效的应用操作。请参阅论文的第 6 节。
来自 Functor、Applicative 和 Monad 的示例 略有改动:
{-# LANGUAGE ApplicativeDo #-}
import Safe (readMay)
-- import Control.Applicative ((<$>), (<*>))
displayAge maybeAge =
case maybeAge of
Nothing -> putStrLn "You provided invalid input"
Just age -> putStrLn $ "In that year, you will be: " ++ show age
yearDiff futureYear birthYear = futureYear - birthYear
maybeAge fS bS = do
fI <- readMay fS
bI <- readMay bS
pure $ yearDiff fI bI
main = do
putStrLn "Please enter your birth year"
birthYearString <- getLine
putStrLn "Please enter some year in the future"
futureYearString <- getLine
displayAge $ maybeAge birthYearString futureYearString
其中 maybeAge
和 do
我用而不是
maybeAge fS bS = yearDiff <$> readMay fS <*> readMay bS
我有 2 个问题:
- 如何检查
maybeAge
在这种情况下使用 Applicative Functor 语义还是 Monad 语义? - 如果使用 Applicative Functor,在这种情况下有什么优势?
关于:ApplicativeDo.
我用你的例子做了一个独立的例子:
{-# LANGUAGE ApplicativeDo #-}
import Text.Read (readMaybe)
displayAge :: Maybe Int -> IO ()
displayAge maybeAge =
case maybeAge of
Nothing -> putStrLn "You provided invalid input"
Just age -> putStrLn $ "In that year, you will be: " ++ show age
yearDiff :: Int -> Int -> Int
yearDiff = (-)
maybeAge :: String -> String -> Maybe Int
maybeAge fS bS = do
fI <- readMaybe fS
bI <- readMaybe bS
pure $ yearDiff fI bI
main :: IO ()
main = do
putStrLn "Please enter your birth year"
birthYearString <- getLine
putStrLn "Please enter some year in the future"
futureYearString <- getLine
displayAge $ maybeAge futureYearString birthYearString
此外,在最后一行中,我交换了参数,因为它们在您的示例中的顺序似乎有误。我还根据@Redu 的评论改进了 yearDif
定义。
这里是您问题的答案。
您可以按照 GHC User Guide 中的建议检查是否确实应用了应用(和仿函数)操作,即使用
-ddump-ds
编译器开关。我在下面添加了几个开关以使输出更简洁。我也只展示了关于maybeAge
函数的摘录。$ ghc appdo.hs -ddump-ds -dsuppress-type-applications -dsuppress-module-prefixes [1 of 1] Compiling Main ( appdo.hs, appdo.o ) ==================== Desugar (after optimization) ==================== Result size of Desugar (after optimization) = {terms: 75, types: 75, coercions: 0, joins: 0/0} ... -- RHS size: {terms: 17, types: 13, coercions: 0, joins: 0/0} maybeAge :: String -> String -> Maybe Int [LclId] maybeAge = \ (fS_a1h3 :: String) (bS_a1h4 :: String) -> <*> $fApplicativeMaybe (fmap $fFunctorMaybe (\ (fI_a1h5 :: Int) (bI_a1h6 :: Int) -> yearDiff fI_a1h5 bI_a1h6) (readMaybe $fReadInt fS_a1h3)) (readMaybe $fReadInt bS_a1h4) ...
当然,这里没有加速。
Maybe
的应用运算具有恒定的复杂性(O(1)
)——就像单子运算一样。在 original paper 中,
ApplicativeDo
的作者给出了几个更复杂的 monadic 类型的例子(Haxl
、Data.Seq
、解析等),允许渐近地更高效的应用操作。请参阅论文的第 6 节。