2016-11-18 2 views
3

내가 합성 목록 주어진 두 개의 목록을 반환하는 기능 구축 :멀티 타입 목록

let l1 = [('a', 1, 'a'); ('b', 2, 'b'); ('c', 3, 'c'); ('d', 4, 'd')] 

기능 : 이제

let rec split2 l = 
    match l with 
    [] -> ([], []) 
    | (x, y)::ls -> let (xs, ys) = 
           split ls in (x::xs, y::ys);; 

val split2 : l:('a * 'b) list -> 'a list * 'b list 

lsts = [('a', 1); ('b', 2); ('c', 3); ('d', 4)] 

split2 lsts;; 
val it : int list * char list = ([1; 2; 3; 4], ['a'; 'b'; 'c'; 'd']) 

을, 나는 더 복잡한 목록 개념을 적용 나는 타입에 문제를 주었다. 그래서 나는 두 번째 타입을 만든다. 이 경우 형식을 신중하게 정의했지만 컴파일해도 l1에 적용하면 오류가 반환됩니다.

let rec split3 (l:(char * int * char) list) =     
    match l with 
    [] -> ([], [], []) 
    | (x, y, z)::ls -> 
        let (xs, ys, zs) = 
            split3 ls in (xs, ys, zs);; 

val split3 : l:(char * int * char) list -> 'a list * 'b list * 'c list 

split3 l1;; 

    error FS0030: Value restriction. The value 'it' has been inferred to 
    have generic type val it : '_a list * '_b list * '_c list  
    Either define 'it' as a simple data term, make it a function with explicit 
arguments or, if you do not intend for it to be generic, add a type annotation. 

왜 형식이 선언 되더라도 추가 형식 주석이 필요합니까?

+0

예. 그래서 두 번째 질문을 생각해 보았습니다. 첫 번째 예제에서는 '두 요소'목록과 두 번째 예제에서는 '세 요소'목록과의 차이점은 무엇입니까? 둘 다 문자와 정수로 구성됩니다. – Worice

+0

첫 번째 코멘트는 무의미했습니다. 컴파일러는 함수의 반환 유형을 유추 할 수 없습니다.'let rec split3 (l : (char * int * char) list) : (char list * int list * char list) = ' – Petr

+1

때때로 값의 이해가 어렵 기 때문에 값 제한 오류가 더 많습니다. https : //blogs.msdn.microsoft.com/mulambda/2010/05/01/finer-points-of-f-value-restriction/ – Petr

답변

6

당신이 찾고있는이 기능은 이미 설명한 두 가지 기능이 다른 FSharp.Core

긴 대답

List.unzip3 : ('T1 * 'T2 * 'T3) list -> 'T1 list * 'T2 list * 'T3 list 

List.unzip3.로 존재

짧은 대답.

val split3 : l:(char * int * char) list -> 'a list * 'b list * 'c list 

이 이해가되지 않습니다 다음 split3 기능 유형 서명에 있음을 알 수 있습니다. 유형 서명은 다음과 같아야합니다.

val split3 : l:(char * int * char) list -> char list * int list * char list 

그렇다면 왜 그런가요?

split2 함수에서 결과를 (x::xs, y::ys)으로 정의하고 split3에서 (xs, ys, zs)으로 정의했음을 유의하십시오. 즉, split3 함수의 결과는 항상 ([], [], [])이지만 빈 목록의 유형은 정의되지 않으므로 값 제한 오류가 발생합니다. 함수의 종류가 올바르게 추론 할 것이다 당신이 수정하면

let rec split3 (l:(char * int * char) list) =     
    match l with 
    | [] -> ([], [], []) 
    | (x, y, z)::ls -> 
     let (xs, ys, zs) = split3 ls 
     (x::xs, y::ys, z::zs) 

, 당신은 형의 주석을 제거 할 수 있습니다 :

이 해결하기 위해 사소한

let rec split3 l =     
    match l with 
    | [] -> ([], [], []) 
    | (x, y, z)::ls -> 
     let (xs, ys, zs) = split3 ls 
     (x::xs, y::ys, z::zs) 

또한이 유형의 함수는 fold이므로 수동으로 작성하는 경우 명시적인 되풀이가 아닌 해당 고차 함수로 작성하는 것이 좋습니다 시온. 나는 원래 목록 순서를 유지하기 위해 foldBack보다는 fold을 사용하고

let split3 l = 
    let folder (x, y, z) (xs, ys, zs) = 
     (x::xs, y::ys, z::zs) 
    List.foldBack folder l ([], [], []) 

참고.

+0

직선적이고 유익한. 멋진 답변에 감사드립니다. 단지 세부 사항 : in은 불필요한가요? 그리고 주석에 명시된 바와 같이, 목록에는 동종 유형이 없어야합니다. – Worice

+1

@Worice F #의 경량 구문과 장황한 구문의 차이점 중 하나는'in','begin' 및'end' (verbose)와 들여 쓰기 (lightweight)의 사용에 대한 요구 사항입니다. 경량 구문이 기본값이며 거의 모든 F #이 사용되므로 거의 항상 'in'이 필요하지 않습니다. 자세한 내용은 여기를 참조하십시오. https://docs.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/verbose-syntax – TheInnerLight

+0

감사합니다. 그게 내가 놓친 것입니다! – Worice

관련 문제