2017-01-26 9 views
6

이의 내가 유형의 견적 있다고 가정 해 봅시다 Quotations.Expr<(int -> int -> int)>일부 응용 프로그램

<@ fun x y -> x + y @> 

내가 reduce 1 expr로 전화했을 때 기본적으로

<@ fun y -> 1 + y @> 

즉, 내가 원하는 얻을 것이라고 기능 fun reduce x expr을 만들려면 부분적으로 인용문을 적용하여 다른 인용문을 만듭니다.

나는 이것이 가능하다고 생각합니다. 아무나 생각을 가지고 있습니까? 이전에 시도 되었습니까? 아무것도 찾을 수없는 것 같습니다.

또한 LISP에 익숙하지 않지만 LISP 매크로를 사용하여 달성 할 수있는 것과 근본적으로 비슷합니까?

업데이트 : 인용문을 줄이는 동안 결과 표현식 트리에서 평가할 수있는 부분을 평가하고 싶습니다.

예 : reduce true <@ fun b x y -> if b then x + y else x - [email protected]><@ fun x y -> x + y @>이됩니다.

+0

동안, 나는 다른 특정 질문을하는 것이 좋습니다. 정말 작고 자급 한 질문과 답변에 빛이납니다. – CaringDev

+0

Understanding @CaringDev – tejas

답변

4

당신이 당신의 인용 양식 fun x ...의 것을 알고 있다면 그것은 쉽게 :

let subst (v:'a) (Patterns.Lambda(x,b) : Expr<'a->'b>) = 
    b.Substitute(fun x' -> if x = x' then Some (Expr.Value v) else None) 
    |> Expr.Cast<'b> 

subst 1 <@ fun x y -> x + y @> 

당신이 추가 표현을 단순화하고 싶은 경우에, 당신이 대답해야합니다 몇 가지 약간 까다로운 질문이 :

  • 부작용이 있습니까? <@ fun x y -> printfn "%i" x @>으로 시작하여 을 1으로 대체하면 <@ fun y -> printfn "%i" 1 @>의 단순화 된 버전은 무엇입니까? 이것은 호출 될 때마다 1을 출력해야하지만, 어떤 표현이 부작용을 일으키는 지 미리 알지 못한다면 거의 모든 것을 단순화 할 수 없습니다. 이것을 무시하면 (표현이 부작용을 일으키지 않는다고 가정 할 때) 충실하게 대처하는 것이 훨씬 간단 해집니다.
  • 단순화가 실제로 의미하는 것은 무엇입니까? 대체 후 <@ fun y -> y + 1 @>이 나온다고 가정 해 보겠습니다. 그런 다음 이것을 let f y = y+1 in <@ f @>에 해당하는 것으로 단순화하는 것이 좋거나 나쁘지 않습니까? 이것은 단지 값을 포함하는 사소한 표현이라는 점에서 분명히 "더 간단"하지만 값은 이제 불투명 한 함수입니다. <@ fun y -> 1 + (fun z -> z) y @>이 있다면 어떻게됩니까? 내부 함수를 값으로 단순화하는 것은 괜찮습니까? 또는 불량입니까? 우리가 부작용을 무시할 수 있으며, 우리가 이제까지 값으로 함수를 대체하지 않으려면

, 다음과 같이 단순화 기능을 정의 할 수 있습니다 :

let reduce (e:Expr<'a>) : Expr<'a> = 
    let rec helper : Expr -> Expr = function 
    | e when e.GetFreeVars() |> Seq.isEmpty && not (Reflection.FSharpType.IsFunction e.Type) -> // no free variables, and won't produce a function value 
     Expr.Value(Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation e, e.Type) 
    | ExprShape.ShapeLambda(v, e) -> Expr.Lambda(v, helper e) // simplify body 
    | ExprShape.ShapeCombination(o, es) -> // simplify each subexpression 
     ExprShape.RebuildShapeCombination(o, es |> List.map helper) 
    | ExprShape.ShapeVar v -> Expr.Var v 

    helper e |> Expr.Cast 

참고하는 것이이 아직도 수도 당신이 원하는만큼 물건을 단순화; 예를 들어 <@ (fun x (y:int) -> x) 1 @>은 단순화되지 않지만 <@ (fun x -> x) 1 @>이됩니다.

+0

이것은 평가할 수있는 부분을 평가하지 않겠습니까? 예를 들어, 'fun bxy -> if b then x + y else x -y' 'subst true true xy expr'은'fun xy -> x + y'가됩니다. – tejas

+0

@tejas - 내 편집 참조 – kvb

+0

고마워요. @ kvb, 계속 할 수있게 해주셨습니다. – tejas

2

접합은 인용에 인용을 삽입하는 편리한 방법입니다 :

let reduce x expr = 
    <@ (%expr) x @> 

reduce 입력이 'a -> Expr<('a -> 'b)> -> Expr<'b>

사용법 : @kvb 대답은 간단하게 표현 유용한 힌트를 제공

let q = <@ fun x y -> x + y @> 
let r = reduce 1 q // Expr<int -> int> 
let s = reduce 2 <| reduce 3 q // Expr<int> 
let t = reduce "world" <@ sprintf "Hello %s" @> // Expr<string> 
+0

스플 라이스 (splicing)에 관해 알아야 할 좋은 점은 있지만, 편집하기 전이라도 질문에 대답하는 것 같지 않습니다. 'reduce 1 q'는'<@ (fun xy -> x + y) 1 @>'가 아니라 '<@ fun y -> 1 + y @>'가됩니다. 의미 론적으로는 동등하지만, 인용문을 다루는 경우 종종 구문 구조에 관심을 갖습니다. – kvb

+0

@kvb 물론입니다! 이것은 더 넓은 관점을 제공해야하며 IMO는 "부분 적용 ..."및 "... 본질적으로 ..."에 적합합니다. 이 질문을 가로막는 다른 사람이 여전히 내 대답을 유용하게 생각할 수 있으므로 당분간 여기에 남겨 두겠습니다. – CaringDev