Является ли реализация F # монодами уникальными по отношению к количеству доступных ему ключевых слов?
Я знаю только F #. Я еще не изучил другие языки функционального программирования. Все примеры, которые я видел для монад, описывают только методы привязки и единицы. F # содержит много ключевых слов (например, let!
, do!
и т.д.), Которые позволяют вам делать разные вещи в одном и том же вычислительном выражении. Это, по-видимому, дает вам больше возможностей, чем ваши основные методы привязки и единицы. Является ли это уникальным для F # или является общим для языков программирования?
Ответы
Ответ 1
Да, я считаю, что синтаксис 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!" };;
Монады - это знакомый пример, который использует операции привязки и возврата выражений вычисления. Например, возможно, монада представляет собой вычисления, которые могут сбой в любой момент:
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 }
Аддитивные монады (aka MonadPlus
в Haskell) - это комбинация из двух. Это немного похоже на монадическое вычисление, которое может создавать несколько значений. Общим примером является список (или последовательность), который может реализовать как 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
обычно принимает некоторую последовательность - хотя это может быть, например, асинхронно).
Ответ 2
Монады определяются в терминах операций bind
и unit
(только). Существуют и другие структуры, которые определяются другими операциями (например, в Haskell, в стандартном классе MonadPlus есть операции zero
и plus
- они соответствуют zero
и Combine
в выражениях вычисления F #). Насколько я знаю, сборщики вычислений F # уникальны с точки зрения обеспечения хорошего синтаксиса для широкого диапазона операций, которые они поддерживают, но большинство операций не связаны с монадами.
Ответ 3
Форматы привязки 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 #". Эти синтаксические формы предлагают способы перегрузить этот синтаксис, например, для кодирования монадических вычислений или моноидальных вычислений и, по-видимому, похожи на, например, о-нотация Haskell и соответствующие (не магические) формы привязок на этом языке.
Поэтому я бы сказал, что они поддерживают некоторую перегрузку синтаксиса для поддержки других интерпретаций синтаксиса выражения языка, и это они имеют общее со многими языками, включая Haskell и OCaml. Это, безусловно, мощная и полезная языковая функция.
Ссылки: Спецификация языка F # 2.0.
Ответ 4
(Вспомните из памяти, я могу отключиться.)
В то время как я думаю, что unit
и bind
являются типичным основанием для монадов, я думаю, может быть, map
и join
для другой основы, которую я видел в научных статьях. Это похоже на то, как LINQ работает в С# и VB, где различные синтаксисы from
помещаются в Select
или SelectMany
, которые похожи на map
и join
. LINQ также имеет некоторые "дополнительные" ключевые слова, немного похожие на F #, хотя и более ad-hoc (и в основном подходят для запросов к перечислениям/базам данных).
Я не знаю других функциональных языков, таких как F #, которые эффективно "поднимают" большую часть потока управления и другого синтаксиса в монады (ну, "выражения вычисления", которые могут быть или не быть монадами).