ApplicativeDo Pragma и Applicative Функтор в Хаскеле - PullRequest
0 голосов
/ 09 декабря 2018

Пример из 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 вопроса:

  1. Как я могу проверить, использует ли maybeAge семантику Applicative Functor или монаду в этом случае?
  2. В чем преимущество в этом случае, если ApplicativeФунктор используется?

О: ApplicativeDo .

1 Ответ

0 голосов
/ 09 декабря 2018

Я сделал самостоятельный пример из вашего:

{-# 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

Кроме того, в последней строке я поменял аргументы, так как они выглядят в неправильном порядке в вашем примере.Также я улучшил yearDif определение согласно комментарию @ Реду.

Вот ответы на ваши вопросы.

  1. Вы можете проверить, что аппликативные (и функторные) операциидействительно применяется, следуя рекомендациям Руководства пользователя GHC , а именно, с использованием ключа компилятора -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)
    ...
    
  2. Скорее всего, здесь не будет никакого ускорения.Аппликативные операции для Maybe имеют постоянную сложность (O(1)) - точно так же, как монадические.

    В оригинальной статье авторы ApplicativeDo приводят несколько примеров более сложных монадических типов (Haxl, Data.Seq, синтаксический анализ и т. Д.), Позволяющих асимптотически более эффективноаппликативные операции.См. Раздел 6 статьи.

...