Haskell: запутался в типе оператора `››=`

Я прорабатываю некоторые вводные материалы по Haskell и в настоящее время изучаю Monads. Я концептуально понимаю, что оператор >>= имеет тип:

(Monad m) => m a -> (a -> m b) -> m b.

В этом контексте я не понимаю, почему следующий код работает, то есть почему он не приводит к несоответствию типов:

main = getLine >>= \xs -> putStrLn xs

Поскольку мы знаем, что getLine :: IO String, я бы предположил, что он может быть «связан» с функцией типа String -> IO String. Однако putStrLn относится к другому типу: putStrLn :: String -> IO ().

Так почему же Haskell позволяет нам использовать >>= с этими двумя функциями?


person iceman    schedule 14.10.2014    source источник
comment
a — это String, m — это IO, а b — это () (единица или пустой кортеж). Таким образом, тип лямбда String -> IO ()   -  person Mephy    schedule 14.10.2014


Ответы (3)


Давайте просто выстроим типы:

(>>=)    ::  m      a -> (     a ->  m  b) -> m b
getLine  :: IO String
putStrLn ::              (String -> IO ())

Здесь у нас есть m = IO, a = String и b = (), поэтому мы можем подставить их в сигнатуру типа >>=, чтобы получить окончательную сигнатуру типа

(>>=) :: IO String -> (String -> IO ()) -> IO ()
person bheklilr    schedule 14.10.2014

() является допустимым типом (называемым единицей, обратите внимание, что он содержит только одно возможное не нижнее значение), и в определении будет b.

a = String и b = () таким образом мы получаем:

IO String -> (String -> IO ()) -> IO ()

person Guvante    schedule 14.10.2014
comment
(Он содержит два значения, второе из которых является нижним. ;) - person Rein Henrichs; 14.10.2014

Поскольку мы знаем, что getLine :: IO String, я бы предположил, что он может быть «связан» с функцией типа String -> IO String.

Почему ты так думаешь? Посмотрите еще раз на сигнатуру типа:

(>>=) :: m a -> (a -> m b) -> m b

Вещь слева m a, вещь справа m b. В частности, бит в середине, a -> m b, говорит о том, что функция, которую вы передаете >>=, принимает a и возвращает m b. Он не говорит, что должен возвращать m a, он говорит, что может быть m b, где b — любой случайный тип. Он не обязательно должен совпадать с a.

В вашем примере лямбда-функция принимает String и возвращает IO (). Итак, a = String и b = (). И это нормально.

person MathematicalOrchid    schedule 14.10.2014