Ru/Monad

From HaskellWiki
< Ru
Revision as of 18:55, 18 September 2007 by Bulatz (talk | contribs) (перенесено из статьи Ru/IO)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

(перенесено из статьи введение в Haskell IO)

Немного глубже в do

Поначалу кажется, что do - какая-то чёрная магия, или встроенный синтаксис для грязных процедур. На самом деле всё это просто cинтаксический сахар, без которого можно обойтись, но который позволяет склеивать процедуры и делает их написание проще.

Для одного выражения do излишне:

main = do putStr "Привет!"

без do можно записать как:

main = putStr "Привет!"

Как же обойтись без do для нескольких действий?

main = do putStr "Как Вас зовут?"
          putStr "Сколько Вам лет?"
          putStr "Неплохой денёк сегодня!"

Тут do говорит, что действия идут одно за другим. Это переводится в оператор последовательности (>>):

main = (putStr "Как Вас зовут?") >> (putStr "Сколько Вам лет?") >> (putStr "Неплохой денёк сегодня!")

Более сложными являются примеры с (<-):

main = do a <- readLn
          print a

Такой код переводится в:

main = readLn >>= (\a -> print a)

Выражения типа (x >>= (\y -> z)) означает "сделать x, взять его результат, подставить его в лямбду вместо y, вычислить z, и сделать z".

С этим оператором можно писать, к примеру, и так:

main = readLn >>= print

Чтобы закрепить принцип избавления от do, рассмотрим внимательно пример программы в трёх вариантах. Сначала идёт do, потом его перевод со скобками, и под конец - без них, что дозволительно благодаря приоритетам операторов:

main  = main3

main1 = do putStr "Как Вас зовут? "
           i <- readLn
           putStr "Сколько Вам лет? "
           v <- readLn
           putStr "Привет, "
           putStr i
           putStr "! Неплохой денёк сегодня!"

main2 = (putStr "Как Вас зовут? ") >>
        readLn >>= (
          \i -> (
            (putStr "Сколько Вам лет? ") >>
            readLn >>= (
              \v -> (
                (putStr "Привет, ") >>
                (putStr i) >>
                (putStr "! Неплохой денёк сегодня!")
              )
            )
          )
        )

main3 = putStr "Как Вас зовут? " >>
        readLn >>= \i ->
        putStr "Сколько Вам лет? " >>
        readLn >>= \v ->
        putStr "Привет, " >>
        putStr i >>
        putStr "! Неплохой денёк сегодня!"

Зачем это всё знать? А все дело в том, что все эти операторы (и do) используются не только в процедурах, а и, к примеру, в списках. Их смысл можно даже переопределять!

Подробнее о списках:

a1 = do x <- [10,100,1000]  -- перебрать все эти числа как x
        y <- [1,2,3]        -- перебрать 1..3 как y
        return (x*y)        -- слить (x*y) в список-результат

-- Результат: [10,20,30,100,200,300,1000,2000,3000]

Но об этих тонкостях лучше прочитать в статье о монадах.