2014-11-12 2 views
2

Можно ли создавать методы или автономные функции в выражении вычисления, которое впоследствии может использоваться одним из канонических методов выражения вычисления?Могу ли я получить доступ к параметрам выражения вычислений?

Я хочу что-то вроде этого:

type FormletBuilder(ctx : HttpContext) = 

    let get_int = 
     match Int32.TryParse (ctx.Request.["foo"]) with 
     | (true, n) -> Some n 
     | _ -> None 

    //similar definitions for get_date, get_non_empty_str, etc... 

    member x.Bind (read : 'a option, f : 'a -> option 'a) = 
     match read with 
     | Some x -> f(x) 
     | None -> None  

    member x.Return (obj) = Some obj 
    member x.Zero() = None 



    let person = formlet ctx { 

     let! id = get_int "id" 
     let! name = get_non_empty_str "fullname" 

     return Person(id, name) 
    } 

Но компилятор жалуется, что get_int не определен.

+0

Что вы на самом деле пытаетесь сделать здесь? Мне кажется, что вы хотите иметь монаду-читателю, а HttpContext - это среда. В этом случае это не будет аргумент строителя, а часть состояния, которое выполняется через вычисление. Тогда вы можете получить свой get_int и т. Д. В отдельном модуле, так как они больше не будут привязаны к строителю, но будут получать HttpContext извне. – scrwtp

+0

@scrwtp - Я скорее подумал, что это была монашка Maybe. Идея состоит в том, что мы читаем значения * и * для разбора значений из объекта HttpContext, но одна или обе эти операции могут потерпеть неудачу (например, мы читаем значение, называемое «id», но не обрабатываем как int). Примерный код немного упрощен; вместо 'Option', мой фактический код использует тип' ReadAttempt <'t> = Успех 't | Ошибка строки. –

+0

Хорошо, справедливо. Я добавлю некоторые из своих мыслей в качестве ответа. – scrwtp

ответ

2

let bindings in class definitions всегда личные. Вместо этого вы можете определить member.

Для простого решения, вы можете сделать:

let formlet = FormletBuilder(ctx) 
let person = formlet { 
    let! id = formlet.get_int "id" 
    ... 
} 
+0

спасибо, но даже если я определяю 'get_int' как член, я все равно не могу использовать его из выражения вычисления. –

+0

Вы правы. Я обновил свой ответ. – Daniel

1

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

  1. Перейти Haskell на нем весь путь и внедрить MaybeReader монады, так что и может быть, и читатель его части явно в типе,
  2. Отложите сахар - Я понимаю, что на самом деле вам не нужен контекст в каких-либо основных конструкторах? Если это так, то, возможно, это не было делом, являющимся аргументом для строителя в первую очередь. Имейте «чистую», возможно, монаду, переместите get_int и т. Д. В соответствующий модуль и попросите их HttpContext явно указать аргумент.
  3. Если вы используете F # 3.0 или новее, вы можете определить get_int и т. Д. Как пользовательские операции рабочего процесса, что должно эффективно дать вам хороший синтаксис, который вы хотите иметь. Вот good post об этом от Tomas Petricek.
  4. Комбинат 2. и 3. - вместо большого количества пользовательских операций, имеют один - ask - который примет функцию HttpContext -> 'a и применит к ней ctx. Эффективно унаследованная версия читателя. Затем вы можете переместить get_int и т. Д. В соответствующий модуль.
+0

Спасибо за продуманный ответ. Вы правы, это было главным образом для сахара. Прежде чем отправлять свой вопрос, я столкнулся с пользовательскими операторами, но они не казались подходящими, так как вам нужно использовать конструкцию 'for..in..do'. Мне нравится # 2 лучшее: я просто расширю «HttpContext», чтобы поддерживать методы, которые мне нужны. –

+0

@RodrickChapman: это удивительно о пользовательских операциях, я бы не ожидал, что они будут привязаны к циклам. Никогда не использовал их сам. – scrwtp

Смежные вопросы