OCAml에서 예외의 유효성을 논하다

12087 단어 ocaml

OCAml에서 예외를 사용하는 이유
나는 나의 OCAml 프로젝트에서 오류 지시 메커니즘으로 result 유형을 보편적으로 사용하려고 한다.그러나 내 경험에 의하면 이것은 ocaml의 존자exn 유형을 대체하기에는 부족하다.
나는 아래에 나의 관찰 결과를 열거했다.
주의: 이것은 경험 보고서입니다. 이상 또는 result 유형을 사용하는 것을 권장하지 않습니다.
아마도 이것은 내가 자신에게 묻는 비슷한 문제의 데이터 포인트가 될 것이다.OCAml 소프트웨어 개발에서 exception 또는 result 유형을 오류 표시 기술로 사용할지 여부의 문제.

오류 보고
Ocaml은 당신의 소프트웨어가 구조를 통해 정확하다는 것을 확보하는 데 아주 긴 길을 걸었다.
그러나 오류는 소프트웨어의 사실이므로 우리는 그것을 처리할 좋은 메커니즘이 필요하다.
이런 메커니즘은 우리가 오류의 출처를 효율적이고 정확하며 정확하게 식별할 수 있도록 해야 한다.
Ocaml 이상 추적, 또는 호출/창고 추적, 바로 이런 도구입니다. 나는 그것이 매우 유용하다는 것을 발견했습니다.그것은 문제가 있는 파일과 그 중의 줄 번호를 제시했다.이로 인해 오류에 대한 조사와 관심을 효율적이고 효율적으로 할 수 있다.result 형식을 사용하면 ocaml 언어와 컴파일러에 내장된 가치 있는 실용 프로그램을 잃게 됩니다.

잘못된 포지셔닝, 재사용 및 API 인체 공학
가령 우리가 일부 ocaml 라이브러리A에서 모듈lib_a을 정의했다면,
module A : sig
  type error = [ `Divisor ]

  val divide : int -> int -> (int, [> error ]) result
end = struct
  type error = [ `Divisor ]
  let divide a b = if b <= 0 then Error `Divisor else Ok (a / b)
end
만약 내가 다른 ocaml 라이브러리 lib_b 를 개발하고 있다면, 그 모듈 B 의 정의는 다음과 같다.lib_b를 사용하고lib_a 따라서 모듈A을 사용합니다.
그러나 모듈B은 컴파일되지 않았습니다.
(* Module B doesn't compile. *)
module B : sig
  type error = [`Some_error]

  val mult_div : int -> int -> (int, [> error]) result
end = struct
  type error = [`Some_error]

  let mult_div a b =
    Stdlib.Result.bind (A.divide a b)
    (fun c ->
      if c < 10 then Error `Some_error else Ok (c * 10))
end
모듈B을 컴파일하기 위해서는 모듈type error = [`Some_error]B 설명을 포기해야 합니다. 아래와 같습니다.
module B1 : sig
  val mult_div : int -> int -> (int, [> `Some_error | `Divisor ]) result
end = struct
  let mult_div a b =
    Stdlib.Result.bind (A.divide a b) (fun c ->
        if c < 10 then Error `Some_error else Ok (c * 10))
end
아마도 우리는 함수 서명 중의 형식 주석을 그다지 개의치 않을 것이다.그러나 B1에서 여러 개의 라이브러리를 사용하고 모든 라이브러리에 특정한 오류가 있으면 이 오류를 표시해야 합니다. 이 상황은 확장되지 않습니다.
그 밖에 우리는 현재 더 많은 오류 포지셔닝 메커니즘을 잃었다. 즉, Divisor 에서 B1.mult_div 에서 오류가 발생한 것 같지만, 정말 그런가?
잘못된 포지셔닝이 잃어버린 단점은 다음과 같이 완화될 수 있다.
module B2 : sig
  type error = [ `A of A.error | `Some_error ]

  val mult_div : int -> int -> (int, [> error ]) result
end = struct
  type error = [ `A of A.error | `Some_error ]

  let mult_div a b =
    match A.divide a b with
    | Ok c -> if c < 10 then Error `Some_error else Ok (c * 10)
    | Error e -> Error (`A e)
end
그러나 그것은 B1와 같은 신축성 결함을 가지고 있다.errormult_div 에서 사용한 모든 오류의 연결입니다.
또한 B2의 사용자는 자신의 오류 유형을 정의하고 다시 포장해야 한다B2.error.그렇게 지도 모른다, 아마, 아마...
module type C = sig
  type error = [ `B of B2.error | `Error_c ]

  val mult_div : int -> int -> (int, [> error ]) result
end
우리는 현재 이미 잘못된 차원 구조를 세웠다.나는 이런 API는 인체공학에 부합되지 않는다고 생각한다.

반복 개발 및 오류 주시
나는 교체 개발을 더욱 좋아한다.예를 들어, 나는 함수를 만들어서 저장하고, utop에 불러와서, 함수의 일련의 입력과 출력을 탐색한다.이 탐색/교체 단계에서 나는 잘못된 사례나 조건에 더 이상 관심을 기울이고 싶지 않다.result를 사용하면 오류 상황을 주의해야 할 수도 있습니다.이 가능하다, ~할 수 있다,...그러나 이 코드는 일회용 코드일 수도 있다.개발의 초기 단계에서 이런 상황이 발생할 가능성이 매우 높다.그래서 너의 교체 속도가 영향을 받을 수도 있다.result 유형을 사용할 때의 잘못된 포지셔닝에 대해서는 상술한 요점을 참고하십시오.
예외를 제외하고, 잘못된 줄 이름과 파일 이름의 위치를 제시했기 때문에, 코드에서 오류가 정확한 위치를 찾으려고 너무 많은 시간을 들일 필요가 없습니다.이것은 교체 속도와 아래에서 위로 올라가는 개발을 높일 것이다.즉, 잘못된 장면을 신속하게 발견하고 추상적이고 봉인된 장면을 더욱 튼튼하게 만들 수 있다.반복됩니다.

구조를 통해 바로잡다
나는 이것이 사용result 유형의 가장 큰 장점과 순이익이 될 것이라고 생각한다.
그러나 내가 그것을 사용한 경험이 없어서 OCAml 소프트웨어의 정확한 구조가 뚜렷하게 줄어들지 않았다.
반대로, 그것을 사용할 때, 나는 이 지표가 어떤 뚜렷한 개선이 있는지 알아차리지 못했다.
시간의 추이에 따라 추상/봉인 메커니즘과 유형 시스템이 정확한 OCAml 소프트웨어를 만드는 데 가장 중요한 역할을 발휘하고 있음을 알아차렸다.

요약
현재 OCAml 개발의 관점은 잘못된 메커니즘으로 사용result을 강조하는 것 같다.그러나 그것을 널리 사용하려고 시도한 후에 나는 그것이 부족하다는 것을 발견했다.특히 OCAml 소프트웨어의 오류를 나타내는 방법으로

좋은 웹페이지 즐겨찾기