Я работал над следующим небольшим фрагментом кода:
import Control.Monad
import Data.Aeson
import qualified Data.HashMap.Strict as HashMap
import Data.Map (Map)
import qualified Data.Map as Map
import GHC.Generics
-- definitions of Whitelisted, WhitelistComment and their FromJSON instances
-- omitted for brevity
data Whitelist = Whitelist
{ whitelist :: Map Whitelisted WhitelistComment
} deriving (Eq, Ord, Show)
instance FromJSON Whitelist where
parseJSON (Object v) =
fmap (Whitelist . Map.fromList) . forM (HashMap.toList v) $ \(a, b) -> do
a' <- parseJSON (String a)
b' <- parseJSON b
return (a', b')
parseJSON _ = mzero
когда я понял, что могу переписать блок do
в аппликативном стиле:
instance FromJSON Whitelist where
parseJSON (Object v) =
fmap (Whitelist . Map.fromList) . forM (HashMap.toList v) $ \(a, b) ->
(,) <$> parseJSON (String a) <*> parseJSON b
parseJSON _ = mzero
и с этим я мог бы также заменить forM
на for
. Прежде чем внести изменения выше, я сначала переключился на for
:
instance FromJSON Whitelist where
parseJSON (Object v) =
fmap (Whitelist . Map.fromList) . for (HashMap.toList v) $ \(a, b) -> do
a' <- parseJSON (String a)
b' <- parseJSON b
return (a', b')
parseJSON _ = mzero
и, к моему удивлению, это все еще скомпилировано. Учитывая определение for
:
for :: (Traversable t, Applicative f) => t a -> (a -> f b) -> f (t b)
Я думал, что ограничение Applicative
не позволит мне использовать нотацию do/return в действии, переданном for
.
Я явно упускаю здесь что-то фундаментальное, либо с точки зрения того, что на самом деле подразумевает подпись for
, либо как код, который я разместил, интерпретируется компилятором, и был бы признателен за любую помощь в понимании того, что происходит.
Applicative
является суперклассомMonad
?forM
,liftM
и т. д. — напоминания о том, чтоApplicative
не был (в Prelude) надклассомMonad
. - person Alec   schedule 14.12.2016return
при наличии ограниченияApplicative
. - person ppb   schedule 14.12.2016parseJSON
работает в монадеParser
, которая также является аппликативной (разумеется).return
(и запись do) проверяет, чтоParser
является монадой -- так оно и есть.for
проверяет, что это также аппликатив - так оно и есть. Все работает просто отлично. - person chi   schedule 14.12.2016