2017-02-08 10 views
0

저는 JaneStreet의 Core 라이브러리에 익숙합니다.Pervasives의 Core의`List.init`?

List.init 5 ~f:(Fn.id);; 
- : int list = [0; 1; 2; 3; 4] 

List.init 5 ~f:(Int.to_string);; 
- : string list = ["0"; "1"; "2"; "3"; "4"] 

그러나,이 기능이 존재하지 않는 것 :

List.init;; 
- : int -> f:(int -> 'a) -> 'a list = <fun> 

그것은 당신이 요소를 초기화하는 사용자 정의 기능을 사용하여 목록을 만들 수 있습니다 : 그 List 모듈은 깔끔한 init 기능을 가지고있다 Pervasives, 이것은 슬프다. 뭔가 빠졌는가, 아니면 직접 구현해야 하는가? 그리고 글을 써야 할 필요가 있다면 어떻게해야합니까?

편집는 :

나는 init의 필수 버전을 작성했습니다,하지만 이러한 경우를 OCaml의 필수 기능에 의존해야 할 권리를 생각하지 않습니다. :(

let init n ~f = 
    let i = ref 0 in 
    let l = ref [] in 
    while !i < n do 
    l := (f !i) :: !l; 
    incr i; 
    done; 
    List.rev !l 
;; 

편집 2 :

나는이 기능을 가지고 OCaml의의 GitHub의에 pull request 열었습니다 포함

+0

일반적인 코멘트 : Pervasives의 어떤 종류의 편의성도 기대하지 마십시오. 전체 표준 라이브러리를 원한다면 현재 코어 또는 컨테이너 또는 배터리 (다른 것들도있을 수 있음)를 사용해야합니다. – user3240588

+0

그래, 나는 이미 그것을 알아 차렸다. – RichouHunter

답변

1

재귀 구현은 매우 간단하지만, 꼬리가 아닙니다.. - 재귀 적입니다. 즉, 큰 목록의 경우 스택 오버플로가 발생할 위험이 있습니다.

let init_list n ~f = 
    let rec init_list' i n f = 
    if i >= n then [] 
    else (f i) :: (init_list' (i+1) n f) 
    in init_list' 0 n f 

우리는 보통의 기술을 사용하여 꼬리 재귀 버전으로 변환 할 수 있습니다

let init_list n ~f = 
    let rec init_list' acc i n f = 
    if i >= n then acc 
    else init_list' ((f i) :: acc) (i+1) n f 
    in List.rev (init_list' [] 0 n f) 

이 제품은 누적를 사용하고 또한 목록이 역으로 구축 될 때, 중간 결과를 반대로 할 필요가있다. 목록 반전을 방지하기 위해 f i 대신 f (n-i-1)을 사용할 수도 있지만 f에 부작용이있는 경우 예기치 않은 동작이 발생할 수 있습니다.

대안과 짧은 솔루션은 단순히 출발점으로 Array.init을 사용하는 것입니다

let init_list n ~f = Array.(init n f |> to_list) 
+0

'Array.init'은'List.init'이 아닌 것입니다? 이것은 부끄러운 일이다. :( – RichouHunter

0

당신은 JaneStreet의 코드를 복사하여 를 사용합니다. 당신은 패키지 CORE_KERNEL에서 core_list0.ml 내 원래의 코드를 찾을 수 있습니다

let init n ~f = 
    if n < 0 then raise (Invalid_argument "init"); 
    let rec loop i accum = 
    if i = 0 then accum 
    else loop (i-1) (f (i-1) :: accum) 
    in 
    loop n [] 
;; 

:

코드는 같은의 (하지만 동일하지 않음)를 찾습니다.