일반적으로 F # 유형 시스템은 입력 된 추상 구문 트리를 사용자의 예제와 같이 (직접적으로) 정의하기에 충분하지 않습니다. 이것은 F #에서 지원되지 않는 generalized algebraic data types (GADTs)을 사용하여 수행 할 수 있습니다 (Haskell과 OCaml에서 사용 가능하지만). F #에서 이것을 사용하는 것이 좋겠지 만 언어가 좀 더 복잡해 졌다고 생각합니다.
변수 변수 'b
이 정의되어 있지 않기 때문에 기술적으로 컴파일러가 불평합니다. 그러나 물론 그것을 정의하면 다른 의미를 갖는 Expr<'a, 'b>
유형이 생깁니다.
F #에서 이것을 표현하고 싶다면 인터페이스를 기반으로하는 해결 방법을 사용해야합니다 (인터페이스에 일반 메서드가있어서 제약 조건을 표현할 수 있습니다). 여기에 exists 'b
과 같은 제약 조건을 표현할 수 있습니다. 이것은 아마 곧 매우 추한 것, 그래서 그것이 좋은 방법이라고 생각하지 않는다,하지만 이런 식으로 뭔가 보일 것이다 :
을 :
// Represents an application that returns 'a but consists
// of an argument 'b and a function 'b -> 'a
type IApplication<'a> =
abstract Appl<'b> : Expr<'b -> 'a> * Expr<'b> -> unit
and Expr<'a> =
// Constant just stores a value...
| Constant of 'a
// An application is something that we can call with an
// implementation (handler). The function then calls the
// 'Appl' method of the handler we provide. As this method
// is generic, it will be called with an appropriate type
// argument 'b that represents the type of the argument.
| Application of (IApplication<'a> -> unit)
이 (fun (n:int) -> string n) 42
의 식 트리를 표현하기를, 당신은 뭔가를 쓸 수
let rec eval<'T> : Expr<'T> -> 'T = function
| Constant(v) -> v // Just return the constant
| Application(f) ->
// We use a bit of dirty mutable state (to keep types simpler for now)
let res = ref None
// Call the function with a 'handler' that evaluates function application
f { new IApplication<'T> with
member x.Appl<'A>(efunc : Expr<'A -> 'T>, earg : Expr<'A>) =
// Here we get function 'efunc' and argument 'earg'
// The type 'A is the type of the argument (which can be
// anything, depending on the created AST)
let f = eval<'A -> 'T> efunc
let a = eval<'A> earg
res := Some <| (f a) }
res.Value.Value
내가 말했듯이, 이것은 조금 정말 극단적 인 해결 방법, 그래서 내가 생각하지 않습니다 :
let expr =
Application(fun appl ->
appl.Appl(Constant(fun (n:int) -> string n),
Constant(42)))
식을 평가하는 기능은 다음과 같이 쓸 수있다 실제로 사용하는 것은 좋은 생각입니다. 이 일을하는 F # 방식이 형식이 지정되지 않은 Expr
유형을 사용하는 것이 겠지요. 프로젝트의 전반적인 목표에 대해 좀 더 자세히 기술 할 수 있습니까 (다른 좋은 접근 방법이있을 수 있습니다)?
명확하고 철저한 설명, 감사합니다! 내가 성취하고자하는 것을 분명하게 설명 할 수 있는지를 볼 수는 있지만, 입력 된 옵션을 열어 두어 주셔서 감사합니다. – TimC
@TimC 도와 줘서 기쁩니다. 이 접근법은 _ 존재하는 유형을 시뮬레이트해야하는 한 오래 사용할 수 있다고 생각합니다. 실제 GADT가 필요한 경우 (사례의 유형이 다른 경우 - 즉'Lambda '가'Expr <'a ->'b> '유형 일 것입니다), 그러면 나는 당신이 쉬운 해결 방법을 찾을 수 없을 것이라고 생각합니다 . –