Есть ли интересные монады одиночного выстрела, кроме "Может быть" и "Любого"?

В языке программирования Монте, как и в его предшественнике E, существует синтаксис для продолжений, разделенных одиночным выстрелом, которые называются "выталкиватели" и являются продолжениями, которые эффективно используются только один раз в пределах синтаксической границы. Например, вот эжектор, который не называется:

escape ej { 42 }

И эжектор, который называется:

escape ej { ej(42); "After 10,000 years, I'm free!" }

Оба оценивают 42, Мы также можем прикрепить действие к случаю, когда эжектор называется:

escape ej { ej(2) } catch result { result + 4 }

Это обо всем этом синтаксисе. Нетрудно представить, как это подражает Maybe или же Either, Я переписываю пример из Haskell Wiki на Maybe в идиоматический Монте:

def f(x, ej):
    return if (x == 0) { ej() } else { x }

def g(x, ej):
    return if (x == 100) { ej() } else { x }

def h(x, ej):
    return g(f(x, ej), ej)

# Monte permits Unicode identifiers but not for free.
def ::"h´"(x, ej):
    def n := f(x, ej)
    return g(n, ej)

(Обратите внимание, как мы должны нести бремя прохождения ej, Монте не хватает "программируемой точки с запятой" в нотации.)

Я не буду делать Either, но это в значительной степени то же самое; возможность добавить catch пункт обеспечивает необходимую дискриминацию типов. Известно, что продолжения с разделителями хорошо известны, поэтому можно создавать сложные инструменты:

def trying(f, g, ej):
    return escape innerEj { f(innerEj) } catch _ { g(ej) }

Такие гаджеты используются, например, в Монте для создания рукописных комбинаторов синтаксического анализа. Итак, в "Матери всех монад" Дэн Пипони объясняет, что Cont в определенном смысле очень Monad на котором многие другие Monad с можно построить. Мы можем попытаться сделать это и в Монте. Давайте использовать стиль Moggi для кодирования монад в объектно-ориентированных языках:

object identity:
    to unit(x):
        return x

    # "bind" is a Monte keyword; we may still use it, but not for free.
    # NB this is `x >>= f` in Haskell.
    to "bind"(x, f):
        return f(x)

И давайте закодировать обязательный помощник i, чтобы понять, как это выглядит:

def i(m, x, ej):
    return m."bind"(x, ej)

... Это не полезно. Это не похоже на хороший синтаксис.

# Haskell: runIdentity $ do { x <- return 32; return $ x // 4 }
escape ej { i(identity, i(identity, identity.unit(32), fn x { identity.unit(x // 4) }), ej) }

В будущем должны были быть классные роботы, а не это. Есть и другая проблема; давайте закодируем другой традиционный Monad, List:

object list:
    to unit(x) { return [x] }

    to "bind"(action, f):
        var rv := []
        for x in (action) { rv += f(x) }
        return rv

И давайте сделаем традиционное декартово произведение. Во-первых, давайте сделаем прямые вычисления; вместо передачи продолжения мы просто свяжем напрямую, используя монаду списка:

▲> i(list, [1, 2, 3], fn x { i(list, [4, 5, 6], fn y { [x * y] }) })
Result: [4, 5, 6, 8, 10, 12, 12, 15, 18]

А теперь с эжектором:

▲> escape ej { i(list, i(list, [1, 2, 3], fn x { i(list, [4, 5, 6], fn y { [x * y] }) }), ej) }
Result: 4

Так! Это довольно интересно. Выполняется вычисление монады полного списка, но эжектор видит только первый элемент в списке. Я подозреваю, что, поскольку эжекторы являются составными, существует способ создать более сложную логическую монаду, которая лучше не вычисляет так много промежуточных результатов.

Мой вопрос заключается в следующем: когда мы преобразуем Maybe а также Either в идиоматическом Монте мы можем ясно видеть, что синтаксис эжектора применяется элегантно. Какие еще есть монады, у которых было бы интересное одиночное поведение, подобное этому? Не чувствуй себя ограниченным Хаскеллом; Монте нетипизирован, поэтому никто не будет избегать вас за монады, которые трудно набрать!

0 ответов

Другие вопросы по тегам