Jan. 19th, 2013

thedeemon: (office)
Недавно видел жалобу на то, что с монадами код разрастается, и простые выражения порой требуют несколько строчек для записи (речь про do-нотацию была). Сейчас осваиваю потихоньку язык Idris - это такой правильный хаскель с полноценными зависимыми типами (о которых чуть позже) и кучей встроенных плюшек для создания eDSL'ей (об этом вероятно еще позже). Так вот, в идрисе для монад сахара еще подсыпали, хочу поделиться. Пусть у нас есть функция readInt типа String -> IO Int, запрашивающая и получающая число откуда-то из внешнего мира, и мы хотим прочитать два числа и вывести их сумму. В языках вроде Clean или ML, где для монад вообще никаких спецсредств нету, это выглядит весьма печально. В хаскеле и идрисе есть привычная всем do-нотация:
main = do
  a <- readInt "a"
  b <- readInt "b"
  print (a+b)

Вот и получилось много строк на ровном месте. Первый кусочек сахара: monad comprehensions. Они когда-то были в хаскеле, потом потерялись, есть ли сейчас - не знаю. Идея в том, чтобы list comprehensions обобщить с монады List на произвольные монады:
main = [a + b | a <- readInt "a", b <- readInt "b"] >>= print

Не особо короче, чем вариант do с фигурными скобками и точками с запятой, но сама идея занятная.

Еще один вариант, доступный и в хаскеле: спрятать весь plumbing в операторы. Это как раз происходит, если вспомнить, что монада это функтор, а в наших языках еще и аппликативный:
class Functor f => Applicative (f : Type -> Type) where 
    pure  : a -> f a
    (<$>) : f (a -> b) -> f a -> f b
и
main = (pure (+) <$> readInt "a" <$> readInt "b") >>= print

(это на идрисе, в хаскеле некоторые значки будут другими, но в целом то же самое)

Второй кусочек сахара: idiom brackets. Специальный синтаксис для аппликативных функторов, где функции автоматически отображаются функтором с помощью pure, а их применения заменяются на применения образов через <$>:
main = [|readInt "a" + readInt "b"|] >>= print

(рассахаривается в предыдущий вариант)
В хаскеле похожая штука есть, но выглядит довольно страшно.

Еще пример для закрепления. Вот такую функцию
m_mul : Maybe Int -> Maybe Int -> Maybe Int
m_mul (Just x) (Just y) = Just (x * y)
m_mul _ _ = Nothing

можно записать как
m_mul x y = [| x * y |]

Profile

thedeemon: (Default)
Dmitry Popov

July 2025

S M T W T F S
  12345
6789101112
13141516171819
20212223242526
27282930 31  

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Aug. 24th, 2025 07:40 pm
Powered by Dreamwidth Studios