2012-08-16 3 views
2

this question의 활성 패턴이 VS 2012 RTM으로 업그레이드 한 후 컴파일되지 않습니다. 형식 테스트를 수행하고 단일 패턴 내에서 리터럴을 일치시키는 방법을 제공합니다. 예를 들어 :패턴 결합 유형 테스트 및 리터럴

let (|Value|_|) value = 
    match box value with 
    | :? 'T as x -> Some x 
    | _ -> None 

let getValue (name: string) (r: IDataReader) = 
    match r.[name] with 
    | null | :? DBNull | Value "" -> Unchecked.defaultof<_> 
    | v -> unbox v 

이는 활성 패턴없이 할 수 있습니까? when 가드 (:? string as s when s = "")를 사용할 수 있지만 다른 패턴과 결합 될 수 없음을 알고 있습니다.

답변

1

KVB의 변화가 유사한 패턴을 생성하기 위해 수정 될 수있다 : 그러나

let (|Value|_|) x value = 
    match box value with 
    | :? 'T as y when x = y -> Some() 
    | _ -> None 

을, 미묘한 성능 차이가있다 . 원래 활성 패턴은 다음과 같이 변환됩니다.

public static FSharpOption<T> |Value|_|<a, T>(a value) 
{ 
    object obj = value; 
    if (!LanguagePrimitives.IntrinsicFunctions.TypeTestGeneric<T>(obj)) 
    { 
     return null; 
    } 
    return FSharpOption<T>.Some((T)((object)obj)); 
} 

즉, 유형 테스트 및 캐스트입니다. 이 변환에 사용 (match x with Value "" -> ...)이다 :

FSharpOption<string> fSharpOption = MyModule.|Value|_|<object, string>(obj); 
if (fSharpOption != null && string.Equals(fSharpOption.Value, "")) 
{ 
    ... 
} 

가장 두드러진 패턴에서 반환 된 값이 입력 패턴 전형적인 컴파일러 변형 (문자열 string.Equals)를 사용하여 일치된다. 일반 어떤지를 사용하고 문자에 대해 매칭보다 효율적

public static FSharpOption<Unit> |Value|_|<T, a>(T x, a value) 
{ 
    object obj = value; 
    if (LanguagePrimitives.IntrinsicFunctions.TypeTestGeneric<T>(obj)) 
    { 
     T y = (T)((object)obj); 
     T y3 = y; 
     if (LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<T>(x, y3)) 
     { 
      T y2 = (T)((object)obj); 
      return FSharpOption<Unit>.Some(null); 
     } 
    } 
    return null; 
} 

:

업데이트 된 패턴으로 변환한다. 평등이 패턴으로 구워지기 때문에 사용법은 조금 더 간단합니다.

FSharpOption<Unit> fSharpOption = MyModule.|Value|_|<string, object>("", obj); 
if (fSharpOption != null) 
{ 
    ... 
} 

어쨌든 작동합니다. 그러나 나는 원래의 것이 더 좋다.

+0

이 작동하지만 중첩 패턴을 사용할 수 없습니다 (매개 변수가있는 활성 패턴의 매개 변수가 일치하는 패턴이 아닌 expression으로 평가되므로). –

+0

오른쪽. 그것이 다른 평등 의미론의 근본 원인이지만 더 간결하게 설명합니다. – Daniel

1

당신은 매개 변수가있는 활성 패턴을 사용할 수 있어야합니다 : 사용법 정확히 당신이 지금 가지고 무엇을 같이한다

let (|Value|_|) v x = 
    if unbox x = v then 
     Some() 
    else None 

합니다.

편집

내가 파괴 변화가 의도적 인 경우, I는 입력 유형과 관련이없는 일반적인 반환 유형 활성 패턴은 일반적으로 피해야한다고 생각 모르겠지만. 형식 유추와 결합하면 미묘한 오류를 쉽게 마스킹 할 수 있습니다. 원래 (|Value|_|) 패턴을 사용하여, 다음 예를 살펴 보겠습니다 :이처럼 보인다

match [1] with 
| Value [_] -> "Singleton" 
| _ -> "Huh?" 

혹시 시도를 실제로 할 일이 아니다 - 이름이 Value는 리터럴로 사용되어야한다는 것을 의미한다; 매개 변수화 된 활성 패턴을 통해이 시나리오를 정확하게 사용할 수 있습니다. (그것은 는 형식 시험에 성공 가정하기 때문에 꽤 같은 일을하지 않습니다)

+0

해결 방법은 약간 다르지만 좋은 방향을 제공합니다. 호환되는 유사 콘텐츠에 대한 내 대답을 확인하십시오. – Daniel

+0

좋은 지적. – kvb

+0

나는 당신의 반례가 짚맨이라고 생각합니다. '(| Value | _ |)', 또는 리턴 타입에서 일반적인 함수는 유추 된 타입을 염두에 두어야합니다. 당신의 예제는'+'에 대해 더 자세히 말합니다. 즉, 피연산자는 인라인되지 않는 한'int'로 추정됩니다. – Daniel