Переписать функцию Haskell без возврата привязки

По совету, который я получил здесь, я пытаюсь переписать функцию без постороннего назначения привязки и возврата, но застрял с дополнительный ввод-вывод, я не могу понять, как из него выбраться.

У меня есть

good :: IO (Either Int String)

getit :: Either Int String -> Int

main :: IO ()
main = do
  x <- fmap getit good
  putStrLn $ show x

главное работает нормально. Но....

main2 :: IO ()
main2 = do
  putStrLn $ show $ fmap getit good

-- let's try totally without do
main3 :: IO ()
main3 = putStrLn $ fmap show $ fmap getit good

main2 терпит неудачу с:

• No instance for (Show (IO Int)) arising from a use of ‘show’
• In the second argument of ‘($)’, namely ‘show $ fmap getit good’
  In a stmt of a 'do' block: putStrLn $ show $ fmap getit good
  In the expression: do { putStrLn $ show $ fmap getit good }

И main3 терпит неудачу с:

• Couldn't match type ‘IO’ with ‘[]’
  Expected type: String
    Actual type: IO String

Как правильно переписать это идиоматически?

(Подвопрос: «‹-» этот парень на самом деле назвал привязкой? Через здесь: Есть ли произносимые имена для распространенных операторов Haskell? )


person Mittenchops    schedule 23.12.2016    source источник


Ответы (2)


Связывание переменных в do-нотации десугирует вызовы комбинатора bind >>=:

do { x <- m ; rest }  =  m >>= \x -> do rest

Итак, ваш пример переводится как:

main = fmap getit good >>= \x -> putStrLn $ show x

Или, в бесточечном стиле:

main = fmap getit good >>= putStrLn . show

Или, используя отношения между fmap и >>=:

main = good >>= putStrLn . show . getit

Для многих монад эта последняя форма будет более эффективной. fmap часто приходится перестраивать отображаемую структуру (например, списки fmap выполняются за время O(n)), тогда как композиция функций всегда составляет O(1).

person Benjamin Hodgson♦    schedule 23.12.2016
comment
И, print = putStrLn . show, так main = good >>= print . getit - person freestyle; 24.12.2016

Я, когда вы искали в Google, как произносится «‹-», вы обнаружили, что, я думаю, вы искали:

main4 :: IO ()
main4 = (fmap show $ fmap getit good) >>= putStrLn

Отсюда:

https://wiki.haskell.org/IO_inside

Более сложный пример включает привязку переменных с помощью «‹-»:

main = do a ‹- readLn print a Этот код разделен на:

main = readLn >>= (\a -> напечатать a)

Но ответ @Benjamin Hodgson лучше, особенно версия, которая вообще не требует fmaps.

И к подвопросу "‹-" desugars to bind, но произносится как "извлечено из" через: https://wiki.haskell.org/Pronunciation

person Mittenchops    schedule 23.12.2016