Является ли реализация F # монад уникальной в отношении количества доступных ей ключевых слов? - PullRequest
15 голосов
/ 13 мая 2011

Я знаю только F #.Я не изучал другие функциональные языки программирования.Все примеры, которые я видел для монад, описывают только методы bind и unit.F # имеет множество ключевых слов (например, let!, do! и т. Д.), Которые позволяют вам делать разные вещи в одном и том же вычислительном выражении.Это, по-видимому, дает вам больше возможностей, чем ваши основные методы привязки и юнитов.Это уникально для F # или распространено в функциональных языках программирования?

Ответы [ 4 ]

19 голосов
/ 14 мая 2011

Да, я думаю, что синтаксис F # для выражений вычислений уникален тем, что обеспечивает прямую синтаксическую поддержку для различных типов вычислений. Может использоваться для работы с моноидами , обычными монадами , а также MonadPlus вычислениями из Haskell.

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

Моноид используется только для объединения значений с использованием некоторой операции "+" (Combine). Вы можете использовать его, например, для построения строк (это неэффективно, но демонстрирует идею):

type StringMonoid() =
  member x.Combine(s1, s2) = String.Concat(s1, s2)
  member x.Zero() = ""
  member x.Yield(s) = s

let str = new StringMonoid()

let hello = str { yield "Hello "
                  yield "world!" };;

Монады являются знакомым примером, в котором используются bind и return операций выражений вычислений. Например, возможно монада представляет вычисления, которые могут в любой момент завершиться с ошибкой:

type MaybeMonad() =
  member x.Bind(m, f) =
    match m with Some(v) -> f v | None -> None
  member x.Return(v) = Some(v)

let maybe = new MaybeMonad()

let rec productNameByID() = maybe {
  let! id = tryReadNumber()
  let! prod = db.TryFindProduct(id)
  return prod.Name }

Аддитивные монады (он же MonadPlus в Хаскеле) представляет собой комбинацию из двух. Это немного похоже на монадическое вычисление, которое может давать несколько значений. Типичным примером является список (или последовательность ), который может реализовывать комбинации bind и :

type ListMonadPlus() =
  member x.Zero() = []
  member x.Yield(v) = [v]
  member x.Combine(a, b) = a @ b
  member x.Bind(l, f) = l |> List.map f |> List.concat

let list = new ListMonadPlus()

let cities = list {
  yield "York"
  yield "Orleans" }
let moreCities = list {
  let! n = cities
  yield n
  yield "New " + n }

// Creates: [ "York"; "New York"; "Orleans"; "New Orleans" ]

Есть несколько дополнительных ключевых слов, которые не соответствуют напрямую какой-либо теоретической идее. Ключевое слово use относится к ресурсам, а for и while могут использоваться для создания циклов. Понимание последовательности / списка фактически использует for вместо let!, потому что это имеет гораздо больше смысла с синтаксической точки зрения (и for обычно принимает некоторую последовательность - хотя она может быть, например, асинхронной).

5 голосов
/ 14 мая 2011

Монады определяются в терминах bind и unit операций (только). Существуют другие структуры, которые определяются другими операциями (например, в Haskell класс типов MonadPlus имеет операции zero и plus - они соответствуют Zero и Combine в выражениях вычисления F #). Насколько я знаю, построители вычислений в F # уникальны с точки зрения обеспечения хорошего синтаксиса для широкого спектра операций, которые они поддерживают, но большинство операций не связаны с монадами.

2 голосов
/ 14 мая 2011

F # связывающие формы, оканчивающиеся на !, обозначают вычислительные выражения , включая let! use! do! yield! return!.

let! pat = expr in comp-expr         -- binding computation

do!  expr in comp-expr               -- sequential computation

use! pat = expr in comp-expr         -- auto cleanup computation

yield! expr                          -- yield computation

return! expr                         -- return computation

Вычислительные выражения используются "для последовательностей и других нестандартных интерпретацийСинтаксис выражения F # ".Эти синтаксические формы предлагают способы перегрузки этого синтаксиса, например, для кодирования монадических вычислений или моноидальных вычислений, и, похоже, похожи, например, на do-notation Haskell и соответствующие (немагические) привязкиформы на этом языке.

Так что я бы сказал, что они поддерживают некоторую перегрузку синтаксиса для поддержки других интерпретаций синтаксиса выражений языка, и это у них общее со многими языками, включая Haskell и OCaml.Это, безусловно, мощная и полезная языковая функция.


Ссылки: Спецификация языка F # 2.0 .

1 голос
/ 14 мая 2011

(Вызов из памяти, возможно, я выключен).

Хотя я думаю, что unit и bind являются типичной основой для монад, я думаю, возможно map и join для другой основы, которую я видел в научных работах. Это похоже на то, как LINQ работает в C # и VB, где различные синтаксические дескрипторы from превращаются в Select или SelectMany, которые похожи на map и join. В LINQ также есть некоторые «дополнительные» ключевые слова, немного похожие на F #, но более специальные (и в основном подходящие для запросов перечислений / баз данных).

Я не знаю ничего о других функциональных языках, таких как F #, которые эффективно «поднимают» большую часть потока управления и другого синтаксиса в монады (ну, «выражения вычислений», которые могут быть или не быть монадами).

...