LINUX.ORG.RU

История изменений

Исправление dave, (текущая версия) :

b - это построитель. В интернете ты, наверное, уже видел один пример построителя: это async. Построитель и определяет то, как задается вычисление.

Что касается While, то его можно определить для любой монады. В общем случае ему нужны лишь Bind и Zero (для монады Zero обычно = return (), а Bind есть монадическая связка):

    let rec whileC p m =
        if p () then 
            bindC m (fun () -> whileC p m) 
        else 
            zeroC

Здесь b.Bind тождественно bindC, b.Zero = zeroC, а b.While = whileC. Просто сначала проще определить функции, а потом - построитель, который является объектом (да, ООП).

Это общее для монад определение while (но не для моноидов!). Точно такое же определение используется в плагине продолжений Scala. Но для многих монад while можно определить часто гораздо эффективнее, и F# это позволяет.

Вместо нотации do в F# берут произвольный построитель и ставят за ним скобки:

b {
    ...
}

Код внутри скобок преобразуется в заданное построителем вычисление. Как я уже писал, такой код мало отличается от обычного кода F#, и в этом главный смысл. while внутри этого кода будет преобразован, как я показал выше.

Если более точно, то тот код получается после:

b {
    while expr do cexpr
}

P.S. На самом деле, там получится что-то вроде

b.Delay (fun () -> b.While ((fun () -> expr), b.Delay (fun () -> "cexpr")))

или даже

b.Run (b.Delay (fun () -> b.While ((fun () -> expr), b.Delay (fun () -> "cexpr"))))

если у построителя определен метод Run, но это детали.

P.P.S. Можно узнать точно, что получилось. Для этого надо использовать «квази-цитирование», и еще надо уметь читать его выхлоп.

Исправление dave, :

b - это построитель. В интернете ты, наверное, уже видел один пример построителя: это async. Построитель и определяет то, как задается вычисление.

Что касается While, то его можно определить для любой монады. В общем случае ему нужны лишь Bind и Zero (для монады Zero обычно = return (), а Bind есть монадическая связка):

    let rec whileC p m =
        if p () then 
            bindC m (fun () -> whileC p m) 
        else 
            zeroC

Здесь b.Bind тождественно bindC, b.Zero = zeroC, а b.While = whileC. Просто сначала проще определить функции, а потом - построитель, который является объектом (да, ООП).

Это общее для монад определение while (но не для моноидов!). Точно такое же определение используется в плагине продолжений Scala. Но для многих монад while можно определить часто гораздо эффективнее, и F# это позволяет.

Вместо нотации do в F# берут произвольный построитель и ставят за ним скобки:

b {
    ...
}

Код внутри скобок преобразуется в заданное построителем вычисление. Как я уже писал, такой код мало отличается от обычного кода F#, и в этом главный смысл. while внутри этого кода будет преобразован, как я показал выше.

Если более точно, то тот код получается после:

b {
    while expr do cexpr
}

P.S. На самом деле, там получится что-то вроде

b.Delay (fun () -> b.While ((fun () -> expr), b.Delay (fun () -> "cexpr")))

или даже

b.Run (b.Delay (fun () -> b.While ((fun () -> expr), b.Delay (fun () -> "cexpr"))))

если у построителя определен метод Run, но это детали.

Исходная версия dave, :

b - это построитель. В интернете ты, наверное, уже видел один пример построителя: это async. Построитель и определяет то, как задается вычисление.

Что касается While, то его можно определить для любой монады. В общем случае ему нужны лишь Bind и Zero (для монады Zero обычно = return (), а Bind есть монадическая связка):

    let rec whileC p m =
        if p () then 
            bindC m (fun () -> whileC p m) 
        else 
            zeroC

Здесь b.Bind тождественно bindC, b.Zero = zeroC, а b.While = whileC. Просто сначала проще определить функции, а потом - построитель, который является объектом (да, ООП).

Это общее для монад определение while (но не для моноидов!). Точно такое же определение используется в плагине продолжений Scala. Но для многих монад while можно определить часто гораздо эффективнее, и F# это позволяет.

Вместо нотации do в F# берут произвольный построитель и ставят за ним скобки:

b {
    ...
}

Код внутри скобок преобразуется в заданное построителем вычисление. Как я уже писал, такой код мало отличается от обычного кода F#, и в этом главный смысл. while внутри этого кода будет преобразован, как я показал выше.

Если более точно, то тот код получается после:

b {
    while expr do cexpr
}