Кстати говоря, некоторые монады позволяют прервать вычисления — например, та же
Maybe с помощью внедрения пустого значения, или монада ошибки, которая вместо пустого значения имеет какую-то информацию и т. д.. Для них используется класс
class Monad m => MonadZero m where
mzero :: m a
// должно выполняться mzero >>= k = mzero
Для прерывания вычислений вставляется
mzero, после чего дальше всё
>>=е пропускается благодаря лени (раз второй аргумент не нужен, не будем вычислять — и тут в JS может получиться упс в некоторых случаях (если только не реализовать force/delay, запутывая всё окончательно; и, опять же, нет макросов для определения delay)). Для улучшения этого есть функция
guard :: MonadZero m => Bool -> m ()
guard False = mzero
guard True = return ()
использующаяся, например, так:
filteredPairs :: [Name] -> [Fruit] -> (Fruit -> Bool) -> (Name -> Fruit -> Bool) -> [(Name, Fruit)]
filteredPairs names fruits isEdible likes = do
fruit <- fruits
guard (isEdible fruit)
name <- names
guard (likes name fruit)
return (name, fruit)
Пример немного искуственный и может быть заменён в этом случае на list comprehension, раз уж тут снова список-монада.
А, даже хитрее. Тогда монады, как отдельного класса и нет, есть просто массив с обновлёнными методами. Ну тоже хлеб интересный.
Именно. В смысле ООП это скорее интерфейс, как я выше говорил.
А классы и другие типы могут быть только инстансами её. Т. к. JS динамический по части интерфейсов, его как бы и не надо нигде писать, только молясь о правильном понимании слов
bind и
return инстансописателем.
Да, вот вы выложили свой вариант - он короче именно потому что range это специальная функция уже возвращающая монаду.
Но так и должно быть. Опять же, как я уже писал, справа от стрелочки выражение типа
m a.