중첩 match
구조를 평평하게하려면 중첩 된 패턴을 사용해야합니다. 이것은 차별화 된 노동 조합 (Brian이 지적한대로)에서 가장 잘 작동합니다. 차별화 된 노동 조합을 사용하도록 F # 코드를 설계하는 것이 최선의 방법입니다.
그렇지 않으면 match
을 사용하여 코드를 간결하게 작성하려는 경우 (활성화 된 패턴을 보여주는 한 가지 예제를 게시 한 ssp).
let (|TryCast|_|) a : 'res option =
match (box a) with
| :? 'res as r -> Some(r)
| _ -> None
let (|Value|) (l:Lazy<_>) = l.Value
첫 번째는 :?
처럼이지만, (as
불가능) 값과 일치하는 둥지 다른 패턴을 수행 할 수 있습니다 : 그러나, 당신은 다음과 같은 두 가지 재사용 가능한 활성 패턴을 사용하여이 작업을 수행 할 수 있습니다. 두 번째 것은 lazy value의 평가를 강요합니다 (둘 다 F # 라이브러리에서 선언 할 수 있다고 가정합니다).지금 당신은 쓸 수 있습니다 :
match lazy cond.EvalBool(), lazy body.Eval() with
| Value(true), Value(TryCast((Break(scope) : ControlFlowModifier)) as e) ->
e :> obj //Break is a DU element of ControlFlowModifier
| Value(true), _ ->
next() //all other values should call next()
| _, _ -> null
편집 : 로저 댓글에서 지적은, 코드의이 버전은 매우 읽을 수 없습니다. 나는 더 나은 옵션은 TryCast
를 사용하고 약간 다르게 원래의 코드를 포맷하는 것입니다 생각 (이 완전히 표준 들여 쓰기 아니지만, 그것은 정확하고 F # 컴파일러 잘 그것을 처리) :
match cond.EvalBool() with
| false -> null
| true ->
match body.Eval() with
| TryCast(Break(scope) as e) -> e :> obj
| _ -> next()
이 아마입니다 대부분의 읽을 수있는 옵션 (이 정말 개인 환경 설정에 따라 다름) 패턴 매칭 기반으로하지만, 당신은 또한 KVB하여 버전으로 처음 match
의 if
instad를 사용하고 TryCast
와 결합 수 :
어떤 경우
if cond.EvalBool() then
match body.Eval() with
| TryCast(Break(scope) as e) -> e :> obj
| _ -> next()
else null
, TryCast
은 하나의 중첩을 피할 때 더 쉽게 읽을 수있는 코드 (:? .. as ..
로 인해 다른 것이 필요함).
질문에 대한 답변은 아니지만 코드가 (:?과'null '을 사용하여) 보이는 경우보다 관용적 인 F # 솔루션이나 래퍼를 고려해보십시오. –