zoukankan      html  css  js  c++  java
  • F# —— Quotation 表达式 (一)

    发如果你看过我前面的一篇关于自定义Type Provide的博客的话,或许你还记得在当时我使用了Quotation表达式来定义TP 中的成员函数。那么Quotation表达式具体有什么作用,有什么用途呢,下面我们来瞧瞧。

    1.   由于Quotation表达式在编译时,并不会被编译成IL代码,所以在当前程序运行时,Quotation表达式会被忽略。这是第一种情况。
    2.   你可以利用F#中的Pattern match分析上面的AST,从而生成新的代码。
    3.  正如上面的说得一样,Quotation表达式不会被编译成IL代码,但是它会被编译成一个树型的数据结构。此结构类似于语法树(AST),因此对此语法树可以进 行分析,将其转换成可以在其他平台上运行的代码(如SQL,GPU等等,其中转换为SQL就相当于C# 中的LINQ 功能)

    在分析其功能之前,我们先看看Quotation 表达式的两种格式:

             第一种:其格式是这样的:  

    let exprInt : Expr<int> = <@ 1 + 1 @>

    即用<@ @> 将代码括起来。此时变量exprInt就会是这样的类型——Expr<’T>此 T为括号中的结果值的类型。 注意Quotation 表达式中的代码必须是完整的代码,也就是说必须有返回值,不能有形如 let exprInt : Expr<int> = <@ let x = 1 + 1 @> 这样的。

        在第一种格式的情况下,我们需要使用%+ 变量名的形式来调用表达式外部的变量, 如:    

    let x = <@ 2 @>
    let exprInt : Expr<int> = <@ (%x : int) + 1 + 1 @>

      第二种:格式如下:  

    let exprNoTy : Expr = <@@ 1 + 1 @@>

        用<@@ @@>将代码括起。 相应的,当引用外部变量时需要使用%%+ 变量名来实现:    

    let y = <@@ 3 @@>
    let exprNoTy : Expr = <@@ (%%y:int) + 1 + 1 @@>

    下面我们来看看第二个功能的示例(第一个功能直接不做处理即可。。):

      

    namespace QuotationExp
    open Microsoft.FSharp.Quotations
    open Microsoft.FSharp.Quotations.Patterns
    open Microsoft.FSharp.Quotations.DerivedPatterns
    
    module Quotation =
        let rec analyzeExpr (expr : Microsoft.FSharp.Quotations.Expr) =
            match expr with
            //如果是<@@ 1 @@>则 执行此代码
            | Int32(value) -> printfn " integer : %d" value
            //如果是<@@ “1“ @@>则 执行此代码
            | String(value) -> printfn "string : %s" value
            //如果是<@@ 1.0 @@>则 执行此代码
            | Double(value) -> printfn "double number : %f" value
    
            //如果是<@@ x @@>则 执行此代码,即 如果是变量就执行此行,如当要分析Lambda 表达式中的参数时 :如分析fun x -> x + 1 中的x
            | Var(var) -> printfn "variable : %A" var
            //如果是<@@ fun x -> x + 1 @@>则 执行此代码
            | Lambda(var,body) -> printfn "lambda expression: %A" body
    
            //当出现的是你指定的函数的时候执行此行, 注意 特定函数必须放在 Call之前
            |SpecificCall <@ (+) @> (inst,methodInfo,[lArg;rArg]) ->
                printfn "calculate the sum of tow arguments : %A, %A" lArg rArg
                analyzeExpr lArg
                analyzeExpr rArg
            //如果表达式是一个函数的时候 且不是上面特定的函数时 执行此行                       
            | Call(callInst,methodInfo,args) ->
                match callInst with
                | Some(inst) -> printfn "%A invoke the method" inst
                | None -> printfn "this is a static method"
                printfn "the method is : %s" methodInfo.Name
                printf "the args of the method: " 
                args |> List.iter(fun x -> analyzeExpr x)
            
            | _ -> printfn "Something else"
    
        let expr = <@@ (2 * 3) * 1 @@>
        analyzeExpr(expr)

    注意:通过分析AST你可以生成自己想要的新代码,也就是在每个 -> 后面的代码,而且每条情况 -> 后面的代码必须是返回相同类型的值。 代码中的Int32 ,String, Double是系统定义的匹配项,因此可以直接进行匹配。

  • 相关阅读:
    技术沙龙.:主题为《代码解析Castle(IOC)应用实例 -开源CMS 系统Cuyahoga》
    Active Record和Domain Object + Dao
    SNMP++.NET 项目
    微软发布Windows Vista Tips and Tricks网站
    2007 Office System Video
    使用搜索引擎搜索结果
    我购买了一台acer笔记本
    有价值的杂志《MSDN杂志》中文版
    Spring2.0中文参考手册(中文版) [转自CSDN论坛]
    开源项目Generics.Net介绍
  • 原文地址:https://www.cnblogs.com/FsharpZack/p/2801241.html
Copyright © 2011-2022 走看看