在元编程中混淆F#语录和模式匹配

Lit*_*ack 11 f# metaprogramming

1-我真的很困惑在元编程上应用F#Quotation&Pattern,请在F#中提出一些方法来解决这个概念.

2-你能告诉我元编程中F#Quotations和Pattern的实际应用吗?

3-有些人说他甚至可以用F#制作另一种语言如IronScheme,是吗?

谢谢.

Jon*_*rop 28

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;}
Run Code Online (Sandbox Code Playgroud)

然后,您可以破解此数据结构,以便将转换应用于您的代码,例如将其从F#转换为Javascript,以便在几乎任何浏览器上运行客户端.

2-你能告诉我元编程中F#Quotations和Pattern的实际应用吗?

在F#报价机制在功能极其有限相比,像OCaml中和Lisp语言的报价机制,到这种地步,我不知道为什么这是有史以来增加.此外,虽然.NET Framework和F#编译器提供编译和全速执行引述代码所需的一切,所引用的代码评估机制是数量级比真正的F#代码,再次使得它变得毫无用处慢几个数量级.因此,除了Websharper之外,我不熟悉它的任何实际应用.

例如,您只能在F#中引用某些类型的表达式,而不能引用其他代码,例如类型定义:

> <@ 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
Run Code Online (Sandbox Code Playgroud)

大多数报价机制允许您引用任何有效的代码.例如,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>)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

元编程是一种应用,其中模式匹配非常有用,但模式匹配是一种通用语言特性.您可能会欣赏我在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>
Run Code Online (Sandbox Code Playgroud)

该OCaml文章被用作F#.NET期刊文章"面向语言的编程:术语级解释器"(2007年12月31日)的基础.

3-有些人说他甚至可以用F#制作另一种语言如IronScheme,是吗?

是的,你可以用F#编写编译器.实际上,F#源自专门为元编程设计的一系列语言,即所谓的MetaLanguages(ML)系列.

来自F#.NET Journal 的文章"使用System.Reflection.Emit运行时代码生成"(2008年8月31日)描述了一种名为Brainf*ck的最小语言的简单编译器的设计和实现.您可以扩展它以实现更复杂的语言,如Scheme.实际上,F#编译器主要是用F#编写的.

在相关的说明中,我刚刚完成了一个编写高性能序列化代码的项目,该代码使用反射来消耗项目中的F#类型,然后吐出F#代码来序列化和反序列化这些类型的值


Tom*_*cek 14

F#引用允许您标记一些F#代码并获取源代码的表示.这是在WebSharper(请参阅本教程)中将F#代码转换为JavaScript.另一个例子是对LINQ的F#支持,其中标记为的代码<@ ... @>被转换为SQL:

let res = <@ for p in db.Products 
               if p.IsVisible then yield p.Name @> |> query
Run Code Online (Sandbox Code Playgroud)

模式匹配只是一种非常强大的语言结构,但它并不比例如更神秘if.我们的想法是,您可以将值与模式匹配,程序将选择第一个匹配的分支.这很有用,因为模式可以嵌套,因此您可以使用它来处理各种复杂的数据结构或实现符号处理:

match expr with
| Multiply(Constant 0, _) | Multiply(_, Constant 0) -> 0
| Multiply(expr1, expr2) -> (eval expr1) * (eval expr2)
// (other patterns)
Run Code Online (Sandbox Code Playgroud)

例如,这里我们使用模式匹配来评估数值表达式的一些表示.第一种模式是一种优化,它处理乘法的一个参数为0的情况.

编写语言您可以使用F#(就像任何其他通用语言一样)为其他语言编写编译器和工具.在F#中,这很容易,因为它带有用于生成词法分析器和解析器的工具.参见例如此介绍.

  • @TomasPetricek - 您曾写过一次虽然Quotations支持类型定义不在F#中,但它将在未来版本中使用.这是2014年.那发生了吗?为什么不? (3认同)