1- Я действительно запутался в применении F # Quotation & Pattern для метапрограммирования, пожалуйста, предложите какой-нибудь подход к этой концепции в F #.
Механизм цитат позволяет вам встраивать код в ваш код и заставлять компилятор преобразовывать этот код из предоставленного вами источника в структуру данных, которая его представляет. Например, следующее дает вам структуру данных, представляющую выражение F # 1+2
:
> <@ 1+2 @>;;
val it : Quotations.Expr<int> =
Call (None, Int32 op_Addition[Int32,Int32,Int32](Int32, Int32),
[Value (1), Value (2)])
{CustomAttributes = [NewTuple (Value ("DebugRange"),
NewTuple (Value ("stdin"), Value (3), Value (3), Value (3), Value (6)))];
Raw = ...;
Type = System.Int32;}
Затем вы можете взломать эту структуру данных, чтобы применить преобразования к вашему коду, например, перевести его из F # в Javascript, чтобы запустить его на стороне клиента практически в любом браузере.
2 - Можете ли вы показать мне какое-нибудь реальное применение цитат F # и паттернов в мета-программировании?
Механизм цитат F # чрезвычайно ограничен по функциональности по сравнению с механизмами цитат таких языков, как OCaml и Lisp, до такой степени, что я удивляюсь, почему он был когда-либо добавлен. Более того, хотя .NET Framework и компилятор F # предоставляют все необходимое для компиляции и выполнения кода в кавычках на полной скорости, механизм оценки кода в кавычках на несколько порядков медленнее, чем в реальном коде F #, что опять же делает его практически бесполезным. Следовательно, я не знаком ни с какими реальными применениями этого помимо Websharper .
Например, вы можете заключать в кавычки только определенные виды выражений, а не другой код, такой как определения типов:
> <@ type t = Int of int @>;;
<@ type t = Int of int @>;;
---^^^^
C:\Users\Jon\AppData\Local\Temp\stdin(4,4): error FS0010: Unexpected keyword 'type' in quotation literal
Большинство механизмов цитирования позволяют вам вообще цитировать любой действительный код. Например, механизм цитат OCaml может заключать в кавычки определение типа, на которое только что наткнулся F #:
$ ledit ocaml dynlink.cma camlp4oof.cma
Objective Caml version 3.12.0
Camlp4 Parsing version 3.12.0
# open Camlp4.PreCast;;
# let _loc = Loc.ghost;;
val _loc : Camlp4.PreCast.Loc.t = <abstr>
# <:expr< 1+2 >>;;
- : Camlp4.PreCast.Ast.expr =
Camlp4.PreCast.Ast.ExApp (<abstr>,
Camlp4.PreCast.Ast.ExApp (<abstr>,
Camlp4.PreCast.Ast.ExId (<abstr>, Camlp4.PreCast.Ast.IdLid (<abstr>, "+")),
Camlp4.PreCast.Ast.ExInt (<abstr>, "1")),
Camlp4.PreCast.Ast.ExInt (<abstr>, "2"))
# <:str_item< type t = Int of int >>;;
- : Camlp4.PreCast.Ast.str_item =
Camlp4.PreCast.Ast.StSem (<abstr>,
Camlp4.PreCast.Ast.StTyp (<abstr>,
Camlp4.PreCast.Ast.TyDcl (<abstr>, "t", [],
Camlp4.PreCast.Ast.TySum (<abstr>,
Camlp4.PreCast.Ast.TyOf (<abstr>,
Camlp4.PreCast.Ast.TyId (<abstr>,
Camlp4.PreCast.Ast.IdUid (<abstr>, "Int")),
Camlp4.PreCast.Ast.TyId (<abstr>,
Camlp4.PreCast.Ast.IdLid (<abstr>, "int")))),
[])),
Camlp4.PreCast.Ast.StNil <abstr>)
FWIW, вот пример в Common Lisp:
$ sbcl
This is SBCL 1.0.29.11.debian, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
* '(+ 1 2)
(+ 1 2)
Метапрограммирование - это одно из приложений, где сопоставление с образцом может быть чрезвычайно полезным, но сопоставление с образцом - это универсальная языковая функция. Вы можете оценить мою статью из «Преимущества OCaml» о минимальном переводчике . В частности, обратите внимание, как простое сопоставление с образцом позволяет ему воздействовать на каждое из различных видов выражения:
> let rec eval vars = function
| EApply(func, arg) ->
match eval vars func, eval vars arg with
| VClosure(var, vars, body), arg -> eval ((var, arg) :: vars) body
| _ -> invalid_arg "Attempt to apply a non-function value"
| EAdd(e1, e2) -> VInt (int(eval vars e1) + int(eval vars e2))
| EMul(e1, e2) -> VInt (int(eval vars e1) * int(eval vars e2))
| EEqual(e1, e2) -> VBool (eval vars e1 = eval vars e2)
| EIf(p, t, f) -> eval vars (if bool (eval vars p) then t else f)
| EInt i -> VInt i
| ELetRec(var, arg, body, rest) ->
let rec vars = (var, VClosure(arg, vars, body)) :: vars in
eval vars rest
| EVar s -> List.assoc s vars;;
val eval : (string * value) list -> expr -> value = <fun>
Эта статья OCaml была использована в качестве основы для статьи в журнале F # .NET «Языковое программирование: переводчик на уровне терминов» (31 декабря 2007 г.) .
3- Некоторые парни сказали, что он может даже создать другой язык, такой как IronScheme, на F #, верно?
Да, вы можете писать компиляторы на F #. Фактически, F # происходит от семейства языков, специально разработанных для метапрограммирования, так называемого семейства MetaLanguages (ML).
В статье "Генерация кода времени выполнения с использованием System.Reflection.Emit" (31 августа 2008 г.) из F # .NET Journal описана разработка и реализация простого компилятора для минимального языка под названием Brainf. * ск. Вы можете расширить это, чтобы реализовать более сложные языки, такие как Scheme. Действительно, компилятор F # в основном написан на самом F #.
В связанной заметке я только что завершил проект, написав высокопроизводительный код сериализации, который использовал отражение для использования типов F # в проекте, а затем выполнил код F # для сериализации и десериализации значений этих типов