2015-09-10 1 views
0

У меня есть немного кода в рабочем процессе, где я хотел бы получить атрибуты для функцииподъемы атрибуты е в безвыходном

выражение это

let! accounts = _accounts() 

и в моем безвыходном У меня есть это

member this.Bind(x,f) = 
    let attributes = 
     f.GetType() 
     .GetCustomAttributes(typeof<myattribute>,false) 

Идея состоит в том, чтобы получить атрибуты функции _accounts(). Однако f представляет собой countinuation, а не _accounts, и поэтому в любом случае я могу получить атрибуты вызываемой функции?

+1

вы можете думать о 'f' здесь как о * остальной части рабочего процесса * - так сложно получить это оттуда (это изменится в зависимости от остальной части вашего кода) – Carsten

+0

Что вы пытаетесь сделать с этим ? – Carsten

+0

Да, ваше право f, конечно, продолжение, и я не могу очень сильно, но я застрял :) –

ответ

5

Я бы сделал один шаг назад - во-первых, вам нужно выяснить, что такое вычисление, которое вы хотите моделировать. Исходя из того, что вы сказали, вы могли бы сохранить результат со списком некоторого журнала аудита информации:

type Audited<'T> = 
    { Log : string list 
    Result : 'T } 

Стандартный базовый расчет строитель будет просто создать пустой журнал в Return и Bind просто сцепить журналы:

type AuditBuilder() = 
    member x.Return(v) = { Log = []; Result = v } 
    member x.Bind(c, f) = 
    let fr = f c.Result 
    { fr with Log = c.Log @ fr.Log } 

let audit = AuditBuilder() 

Вы могли бы на самом деле просто использовать это, при условии, что ваша accounts функция будет возвращать правильное значение Audited<'T>:

let accounts() = 
    { Result = 40 
    Log = ["accounts"] } 
let stocks() = 
    { Result = 2 
    Log = ["stocks"] } 

audit { 
    let! a = accounts() 
    let! s = stocks() 
    return a + s } 

Теперь вопрос в том, можем ли мы сделать это немного лучше, так что accounts() не обязательно должна быть специальной функцией. Вы можете сделать это по-разному - но это больше вопрос о создании значений Audited<'T> сейчас!

Одним из способов сделать что-то подобное было бы передать цитату Bind. Очень простой и простая реализация выглядит следующим образом:

let plain() = 123 

open Microsoft.FSharp.Quotations 

type AuditBuilder with 
    member x.Bind(e:Expr<'T>, f:'T -> _) = 
    match e with 
    | Patterns.Call(None, mi, []) -> 
     let r = f (mi.Invoke(null, [| |]) :?> 'T) 
     { r with Log = r.Log @ [mi.Name] } 
    | _ -> failwith "invalid" 

Это добавляет перегруженный Bind, что позволяет «звонить» в кавычках функция, но она автоматически извлекает имя:

audit { 
    let! p = <@ plain() @> 
    return p } 

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

+0

Определенно ставит меня в положение, в котором я могу продолжить.Простая версия не будет работать, потому что метаданные функции определяют, как будет проходить аудит. Функция будет отмечена различной информацией относительно аудита. Мы можем потребовать по закону отслеживать, кто вызывает указанную функцию, тогда как в других случаях могут быть другие требования, и поток может завершиться неудачно на основе сочетания требований аудита и пользователя. Короче говоря (метаданные) могут влиять на поток вычислений. –