Могу ли я использовать карту на монады? - PullRequest
0 голосов
/ 21 января 2020

Я новичок в концепции монад, и мне нужно использовать Writer Monad. Вот мой код:

newtype WriterLS a = Writer { runWriter :: (a, [String]) } 

instance Monad WriterLS where
  return va = Writer (va, [])
  ma >>= k = let (va, log1) = runWriter ma
                 (vb, log2) = runWriter (k va)
             in  Writer (vb, log1 ++ log2)

instance Applicative WriterLS where
  pure = return
  mf <*> ma = do
    f <- mf
    a <- ma
    return (f a)       

instance Functor WriterLS where              
  fmap f ma = pure f <*> ma 

tell :: String -> WriterLS () 
tell log = Writer ((), [log])

logIncrement :: Int  -> WriterLS Int
logIncrement x = do
                  tell ("Increment:" ++ show x)
                  return (x+1)

logIncrementN :: Int -> Int -> WriterLS Int
logIncrementN x n =    if (n == 1 ) then logIncrement x 
                       else 
                          do
                            y <- logIncrement x
                            logIncrementN y (n-1)

isPos :: Int -> WriterLS Bool
isPos x = if (x>= 0) then (Writer (True, ["poz"])) else (Writer (False, ["neg"]))                           

mapWriterLS :: (a -> WriterLS b) -> [a] -> WriterLS [b]
mapWriterLS f xs = undefined

Теперь я хочу применить карту к WriterLS в функции mapWriterLS, которая на данный момент не определена. Если я вызываю функцию isPos, как map runWriter $ map isPos [1,-2,3], она отображает вывод:

[(True,["poz"]),(False,["neg"]),(True,["poz")]

Когда я вызываю runWriter & mapWriterLS isPos [1,-2,3], мне нужен вывод:

([True, False, True], ["poz","neg","poz"]). 

1 Ответ

0 голосов
/ 21 января 2020

Учитывая действие

foo :: Int -> WriterLS Bool
foo x
  | x >= 0 = tell "poz" >> return True
  | otherwise = tell "neg" >> return False

, вы можете сделать runWriter (Writer (1, []) >>= foo), чтобы получить (True,["poz"]). Но выглядит приятнее сказать runWriter (return 1 >>= foo), поскольку вы превратили return в вспомогательную функцию, которая абстрагирует подробности о записанном списке.

Следующим шагом может быть написание действия

foos :: [Int] -> WriterLS [Bool]
foos [] = pure []
foos (x:xs) = do
  b <- foo x
  bs <- foos xs
  return (b:bs)

где вы можете сделать runWriter (pure [1,-2,3] >>= foos) и получить

([True,False,True],["poz","neg","poz"])

Тогда вы достигли своего результата более конкретным способом, но вы не обобщили рекурсивную часть foos в некоторые Карта как функция, как вы хотите. Я думаю, что это легче, если вы знакомы с происходящей рекурсией.

Как намекает Виллем, когда вы говорите «карта», вы, вероятно, захотите взглянуть на fmap, так как WriterLS - это Functor, что является математическим способом сказать, что он сопоставим в том смысле, к которому вы стремитесь. И, как подсказывает Чепнер, если вы откроете GHCi и наберете :t fmap foo, вы получите:

λ> :t fmap foo
fmap foo :: Functor f => f Int -> f (WriterLS Bool)
fmap foo :: [Int] -> [WriterLS Bool] -- when f = []

, что довольно близко, но не совсем так же, как [Int] -> WriterLS [Bool]. Затем вы могли бы спросить у Google о чем-то, что напоминает недостающую часть, Monad m => [m a] -> m [a].

...