Functor, Applicative, and 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
我有两个问题:
maybeAge
是否使用Applicative Functor语义或Monad?关于:ApplicativeDo。
答案 0 :(得分:2)
我从您身上做了一个完整的例子:
{-# 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
的作者给出了一些更复杂的单子类型(Haxl
,Data.Seq
,解析等)的示例,从而使渐近效率更高应用操作。请参阅本文的第6节。