2012-12-15 2 views
3

겉으로는 사소한 문제가 있습니다. 포인트가없는 방식으로 작성된 함수에서 예외를 처리 할 수 ​​없습니다. 두 기능은 겉으로는 동일하지만 서로 다른 유형이,포인트가없는 함수에서의 예외 처리

let divide1 x y = 
    try 
     x/y 
    with 
     | :? System.DivideByZeroException -> 42 

let divide2 = 
    try 
     (/) 
    with 
     | :? System.DivideByZeroException -> fun _ _ -> 42 

let x1 = divide1 5 0 // works fine 
let x2 = divide2 5 0 // doesn't handle an exception 

:

이 두 기능을 고려

val divide1: int -> int -> int 
val divide2: (int -> int -> int) 

물론, divide2도 예외를 처리하지 않습니다. 단순히 연산자를 반환합니다.

divide2이 적절한 방법으로 예외를 처리하도록하려면 어떻게해야합니까? (특히 인수를 선언하는 것을 제외하고)?

+4

글쎄, 이것은 예상된다. 함수를 반환하고 성공하려고 시도합니다. 나중에이 함수를 호출 할 때 예외가 발생합니다. F # 커뮤니티가 point-free 이상이라고 생각 했나요? ;) –

+0

@ 로버트 : 나는 그 마지막 문장까지 너와 함께했다. ;-( – ildjarn

+0

@ildjarn : 이유는 무엇입니까? point-free 문자는 더 적습니다. 그러나 point-free가 가독성을 떨어 뜨리지 않는 단일 사례를 보지 못했을 것입니다 .F #에서 우리가 intellisense에 의존하는 추가 마이너스 그리고 매개 변수 이름이 손실됩니다. –

답변

7

이것이 포인트없는 스타일이 문제가되는 이유 중 하나입니다. try .. with (또는 표준 루프 및 다른 F # 기능)과 같은 표준 언어 구문을 사용하기 어렵게 만들고 사용자 정의 결합 자로 바꿔야합니다.

let tryWith2 f h a b = 
    try f a b // Call the function with two arguments 
    with e -> 
    // Try running the error handler with the exception 
    match h e with 
    | Some g -> g a b // Error handler provided another function 
    | _ -> reraise() // Error was not handled - reraise 

그런 다음이 같은 점없는 스타일로 기능을 쓸 수 있습니다 (오류 처리가 NOT- 여전히 :이 경우, 예외 핸들러에서 2 개의 인수를 함수를 래핑 콤비가 tryWith2 정의 할 수 있습니다 무료 포인트,하지만 난 물론

let divide2 = 
    tryWith2 (/) (function 
     | :? System.DivideByZeroException -> Some(fun _ _ -> 42) 
     | _ -> None) 

let x1 = divide2 5 0 // returns 42 
let x2 = divide2 5 1 // returns 5 

)이 너무 바보 :-)을 만들고 싶어하지 않는, 지점 무료 스타일도 F #으로 유용합니다. 예를 들어, DSL을 작성할 때 선언적 사양을 작성하는 좋은 방법입니다 (프리미티브는 더 높은 수준의 추상화를 사용하여 표현하기 때문입니다). 여기서, 당신은 정상적인 F # 코드에 매우 가까운 것을 표현할 필요가 있으며, 이것은 정상적인 F # 코드로 가장 잘 표현되는 것이라고 생각합니다.

+0

이것은 내가 두려워했던 것입니다. 예외에 대한 모든 이유는 원하는 곳에서 처리 할 수있는 능력입니다. 한 번에 처리기를 전달해야한다면 ' /)'결과가'Option'입니까? – bytebuster

3

기억해야 할 것은 divide2에 X를 Y로 나눈 값을 반환하지 않고 X를 Y로 나누는 함수를 반환한다는 것입니다. let 바인딩의 코드는 함수 구문이 제공되지 않습니다. 의는 더 이상 작동 구문을 모두 분할 바인딩을 살펴 보자 : 이런 식으로 표시하면

let divide1 = 
    fun x -> 
     fun y -> 
      try 
       x/y 
      with 
       | :? System.DivideByZeroException -> 42 

let divide2 = 
    try 
     fun x -> 
      fun y -> 
       x/y 
    with 
     | :? System.DivideByZeroException -> fun _ _ -> 42 

, 두 개의 정의가 어떻게 다른지 명확해야한다. try 블록은 완전히 다른 위치에 있으며 다른 시점에 실행됩니다.

기존 함수에 예외 처리와 같은 논리를 추가하는 유일한 방법은 divide1에서 수행하는 것처럼 또는 Tomas에서 보여준 것처럼 더 높은 순서 함수로 포장하는 것입니다.