2016-12-16 2 views
4

Итак, я стал довольно зависимым от выражений вычисления f # и пользовательских сборщиков. Я должен использовать C# для большей части моей повседневной работы, но все же хочу использовать выражения LINQ с моими собственными монадами/моноидами. Кто-нибудь знает, есть ли метод C# analog to f # Zero?LINQ эквивалент строителя f #. Zero()?

Relevant f# docs

Вот что я делаю в F #:

type OptionBuilder() = 
    member x.Bind(v,f) = Option.bind f v 
    member x.Return v = Some v 
    member x.ReturnFrom o = o 
    member x.Zero() = Option.None 

let option = OptionBuilder() 

// Example usage (I want something similar from c#) 

let t : Option<int> = 
    option { if false then return 5 } 

ответ

10

Я не знаю точно, что вы просите здесь, но я дам ему выстрелили. Поясните вопрос.

эквивалент в C# на if, не else в монадическом рабочем процессе:

from a in b 
where c(a) 
select a 

Логически это эквивалентно (используя Bind, Return и ноль)

Bind(b, a => c(a) ? Return(a) : Zero) 

Но C# не опускает предложение where в SelectMany (это то, что C# вызывает Bind). C# понижает где положение в понимании запроса на вызов к

Where(M<T>, Func<T, bool>) 

Короче: C# имеет произвольные монадических рабочие процессы в виде постижений запроса; любой монадический тип с методами Select, SelectMany, Where и т. д. может использоваться в понимании. Но на самом деле он не обобщает аддитивные монады с явным нулем. Скорее, «Где» ожидается наличие семантики операции привязки, о которой я говорил выше: она должна иметь тот же эффект, что и привязка единственного значения к концу, если элемент соответствует предикату, а нулевое значение - нет.

Plainly «Where» для последовательностей делает это. Если у вас есть [a, b, c] и вы хотите отфильтровать b, это то же самое, что и объединение [[a], [], [c]]. Но, конечно, было бы безумно неэффективно реально строить и конкатенировать все эти маленькие последовательности. Эффект должен быть таким же, но фактические операции могут быть намного более эффективными.

C# действительно предназначен для поддержки очень специфических монадов: последовательность монад через yield и понимание запросов, продолжение comonad через await и так далее. Мы не проектировали его, чтобы разрешить произвольные монадические рабочие процессы, как вы видите в Haskell.

Ответит ли это на ваш вопрос?

2

Наряду с отличным ответом Эрика, вот некоторый код:

 var result = 
     from value in Option.Some(5) 
     where false 
     select value; 

С # LINQ понимание ищет соответствующий метод расширения, Where. Вот пример реализации:

public static Option<T> Where<T>(this Option<T> option, Func<T, bool> condition) 
     { 
      if(option is None || !condition(option.Value)) 
       return None; 

      return option; 
     } 

Where сам должен определить случай нулевой.

+2

Действительно, 'where false' должен иметь семантику, чтобы результат был нулевой монадой. Это хорошая идея. Из этого мы можем видеть такие вещи, как: нуль 'IObservable ' монада должна быть наблюдаемой последовательностью, которая * никогда * не вызывает 'OnNext'.Итак, небольшая головоломка: что такое нуль 'Task '? –

+0

Поскольку не может быть разрешено логически возвращать результат, есть только один выбор: 'Task.FromCanceled (new CancellationToken (true))' – Asti

+0

Это разумный выбор, но не единственный; другие возможности - это еще одна задача, которая имеет завершение исключения, или задачу, которая выполняется навсегда и никогда не завершается. –