fff :: Int -> Maybe Int
fff i = do
(+10)
<$> Just i
Почему приведенный выше синтаксис считается допустимым?
Потому что он анализируется как
fff i = do { -- do { A } is just
(+10) } -- A
<$> Just i
что эквивалентно
fff i =
(+10)
<$> Just i
потому что <$> Just i
само по себе является недопустимым выражением (поэтому fff i = ((+10) >>= (\i -> fmap (Just i))) i
является неправильным переводом), и это ограничивает размер блока do
в соответствии с правилом, указанным в ответе @chi.
Действительно, его тип выводится как
fff :: Num b => b -> Maybe b
Второй пример работает, если вы добавите пробел перед <$>
в последней строке. Без пробела он снова анализируется как
inputTest :: FormInput -> IO (Either [String] (Int, Int))
inputTest fi = do {
allErrors' <- undefined :: IO [String]
undefined }
<$> ((liftM2 ) (,) <$> undefined <*> undefined) fi
потому что <$> ...
само по себе является недопустимым выражением. Действительно, когда я добавляю явные разделители,
inputTest2 :: String -> IO (Either [String] (Int, Int))
inputTest2 fi = do {
allErrors2 <- undefined :: IO [String] ;
undefined }
<$> ((liftM2 ) (,) <$> undefined <*> undefined) fi
Я получаю точно такое же сообщение об ошибке в TIO (пришлось использовать String
вместо вашего типа).
Начиная с первого undefined :: IO [String]
, весь блок do имеет некоторый тип IO t
, и мы не можем отобразить это ни на что.
Всегда добавляйте все явные разделители (в дополнение к хорошему стилю отступов), чтобы избежать этой странной хрупкости синтаксиса.
Ваш новый пример
x :: Maybe Int
x = do -- { this is
_ <- Just 1 -- ; how it is
undefined -- } parsed
<$> Just 5
Код изменился, но ответ тот же. Блок do
перед блоком <$>
равен Maybe t
(из-за Just 1
), и мы не можем отобразить это.
Снова сделайте отступ в последней строке, и она скомпилируется, потому что undefined <$> Just 5
теперь будет проанализировано как одно выражение.
person
Will Ness
schedule
07.03.2020
Do
-нотация объяснена в цветах. - person Will Ness   schedule 07.03.2020<$>
- это бинарный оператор infix. - person Will Ness   schedule 07.03.2020<$> Just i
само по себе является неправильным выражением. - person Will Ness   schedule 07.03.2020<$>
равенMaybe t
(из-заJust 1
), и мы не можем fmap это. - person Will Ness   schedule 07.03.2020>>=
и>>
с правильным отступом, и это так же удобно для чтения и поддержки, как и предположительно императивное, но иногда обманчивое нотация do. Код Haskell не должен выглядеть императивным. Считать ли нотации вредными - person Redu   schedule 07.03.2020fff = do
//_ <- pure $ Just 100
//(+10)
//<$> Just 50
, если вы удалитеpure $
, произойдет сбой. из-заpure
блок do может быть любого монадического типа, поэтому для соответствия(+10)
он становится((->) r) t
, поэтому на самом делеfff = (\r -> let _ = const (Just 100) r in (+10) r) <$> Just 50
(что действительно эквивалентно(+10) <$> Just 50
. конечно, каждая строка должна быть в контексте Maybe, который (+10) не вы пропустил тамpure
, что делает контекст полиморфным,Just 100
— это просто чистое значение. - person Will Ness   schedule 08.03.2020