2011-10-03 3 views
2

나는 다음과 같은 코드에서 Bitstring module을 사용하고 있습니다 : 당신이 BITSTRING { vv : 32 } 있을 때 절가 Int32 값 것으로 예상된다펑터가 필요한 경우입니까?

let build_data_32 v wid = 
    let num = wid/32 in 
    let v' = Int32.of_int(v) in 
    let rec aux lst vv w = match w with 
    0 -> lst 
    | _ -> (BITSTRING { vv : 32 }) :: (aux lst (Int32.succ vv) (w-1)) in 
    Bitstring.concat (aux [] v' num) ;; 

참고. 이 함수를 비트 스트링의 다른 너비로 작업하도록 일반화하고 싶습니다. 즉, 비트 문자열이 BITSTRING { vv : n }으로 생성 될 build_data_n 함수를 만들고 싶습니다.

그러나 n은 32보다 작 으면 위에 사용 된 succ 함수는 int 유형의 succ 일뿐입니다. 이 32 이상이라면 그것은 라인 let v' = Int32.of_int(v) in에 위 같은 문제 Int64.succ 것 - 값 미만 32 이상 단순히 다음과 같습니다 let v' = v in, 32보다 큰 값이 될 것이다 반면 : let v' = Int64.of_int(v) in

이는 경우가 이 함수를 일반화하기 위해 펑터가 유용 할 것입니다. 그렇다면 어떻게 설정합니까? (그리고 펑터를 필요로하지 않는 다른 방법이 있다면, 그것도 잘 알고 좋을 것이다)

답변

2

, 즉 실행 시간 지정 필드 길이를 사용 vv 유형 정도로 vvint64가 강제, n에 의존 할 수 없다.

+0

필드 길이 (위의 n)에 변수를 사용하면 vv가 항상 int64가되도록 강요한다는 말입니까? – aneccodeal

+0

아, 그래, 나는 네가 무엇을 얻고 있는지 보았다. # let get_bitstring v n = BITSTRING {v : n} ;; val get_bitstring : int64 -> int -> Bitstring.bitstring = aneccodeal

4

이용 가능한 접근법이 몇 가지있다. 나중에 OCaml의 3.12.0 이상을 사용하는 경우, 마지막으로

(* A record to hold the relevant functions *) 
type 'a wrapper_t = { x : 'a; succ : 'a -> 'a } 

(* Use values of type 'a wrapper_t in *) 
let build_data v = 
    v.succ v.x 

(* Helper function to create 'a wrapper_t values *) 
let make_int32_wrapper x = { x = Int32.of_int x; succ = Int32.succ } 
let make_int64_wrapper x = { x = Int64.of_int x; succ = Int64.succ } 

(* Do something with a wrapped int32 *) 
let foo32 = build_data (make_int32_wrapper 12) 
let foo64 = build_data (make_int64_wrapper 12) 

그리고 :

(* The signature a module needs to match for use below *) 
module type S = sig 
    type t 
    val succ : t -> t 
    val of_int : int -> t 
end 

(* The functor *) 
module Make(M : S) = struct 
    (* You could "open M" here if you wanted to save some typing *) 
    let build_data v = 
    M.succ (M.of_int v) 
end 

(* Making modules with the functor *) 
module Implementation32 = Make(Int32) 
module Implementation64 = Make(Int64) 

let foo32 = Implementation32.build_data 12 
let foo64 = Implementation64.build_data 12 

또 다른 레코드에서 데이터 형식을 래핑하는 것입니다 : 하나는 다음과 같은 펑터를 사용하는 것입니다

(* You can use the module type S from the first example here *) 

let build_data (type s) m x = 
    let module M = (val m : S with type t = s) in 
    M.succ x 

let int32_s = (module Int32 : S with type t = Int32.t) 
let int64_s = (module Int64 : S with type t = Int64.t) 

let foo32 = build_data int32_s 12l 
let foo64 = build_data int64_s 12L 

이러한 각각의 방법을 혼합하여 매치 할 수 있습니다. 비슷한 결과를 얻으려면 변형 유형이나 객체에 값을 래핑 할 수도 있습니다. 이 일정 이상 컴파일 시간이 아니므로 BITSTRING { vv : n } 함께

+1

솔직히 말해서, 귀하의 솔루션은 초보자 용 질문에 대한 회신을하기에는 너무 복잡하다고 생각합니다. 나는 일류 모듈이 새롭고, 재미 있고 재미 있다는 것을 알고 있지만 우선 단순성을 우선해야한다. 이 경우 ygrek에 의해 설명 된 BITSTRING 간섭이 없다면 간단한 해결책은'build_data' 함수의 매개 변수로'of_int'와'succ'를 전달하는 것입니다. 나는 당신이 많은 상용구를 가진 세 가지 솔루션을 제공한다는 것을 혼란스럽게 생각하지만,이 것은 아닙니다. – gasche

+0

@gasche : 예, 매개 변수로 of_int와 succ 함수를 전달하는 것이 가장 쉽습니다 ... ygrek에서 설명한 문제를 제외하고. 그럼에도 불구하고 일류 모듈 솔루션을 보는 것은 흥미 롭습니다. – aneccodeal

관련 문제