2010-06-23 2 views
2

나는 Ocaml을 배우고 있으며이를 어떻게 처리 해야할지 잘 모르고있다.ocaml 데이터 유형에 액세스하고 값을 재귀 적으로 수정하는 방법은 무엇입니까?

다음은 예입니다.

는 이제
type xml = Element of tag * xml list | CharData of string;; 

말을하자 나는 태그 값에 액세스하고 수정하려는.

내가 생각할 수있는 방법은 내가이 재귀 구문 아니라는 것을 알고

match xml with 
    Element (tag, xlist) -> (* do something *) 
| CharData str -> (* do something *) 

,하지만 난 당신이 무엇을 의미합니까, 먼저이

답변

4

질문을 이해하면 두 가지 방법으로 원하는 것을 얻을 수 있습니다.

당신은 다음의 예와 같이, 태그의 종류에 변경 가능한 데이터 구조를 사용

type tag = string ref;; 
type xml = Element of tag * xml list | CharData of string;; 

let xml_test = Element (ref "person", 
    [CharData "text0"; 
    Element (ref "phoneNumber", [CharData "text2"]); 
    CharData "text1"; 
    Element (ref "phoneNumber", [CharData "text3"])]);; 

let modify_tag tag new_value= 
    tag := new_value;; 

let rec modify_and_print_xml xml = 
    match xml with 
     Element (tag, xlist) -> modify_tag tag (!tag^"_modified"); 
           print_string (!tag); print_newline(); 

           (*here you do the recursive call*) 
           List.iter (fun element -> modify_and_print_xml element) xlist 

     |CharData str -> print_string str; print_newline();; 

modify_and_print_xml xml_test;; 
그렇지 않으면

하고 함수형 프로그래밍에 새로운 있기 때문에, 가장 좋은 방법은 그것에 대해 생각하려면를 수정하지 않습니다 태그 값을 수정하지만 수정 된 태그가있는 새 xml 값을 생성하십시오 (이것은 순전히 기능을 코딩하고 부작용을 제거하기 위해 수행해야합니다). 여기

, 당신은 "전화"에서 "PHONENUMBER"라는 이름의 모든 태그를 수정 싶은 말은 예입니다

let rec get_modified_xml xml = 
    match xml with 
     Element (tag, xlist) -> if (!tag = "phoneNumber") then 
            Element(ref "phone", List.map (fun element -> get_modified_xml element) xlist) 
           else 
            Element (tag, List.map (fun element -> get_modified_xml element) xlist) 
     | _ -> xml;; 


get_modified_xml xml_test;; 

출력 :

- : xml = 
Element ({contents = "person"}, 
[CharData "text0"; Element ({contents = "phone"}, [CharData "text2"]); 
    CharData "text1"; Element ({contents = "phone"}, [CharData "text3"])]) 
2

잘 다루는 적어도 방법을 알고 싶어요 "수정"? 새로운 변경 값을 반환하는 것이 좋습니까? 아니면 실제로 원래 구조를 변경해야합니까? OCaml에서 변경할 수있는 것은 배열 요소, 문자열 요소, 명시 적으로 변경할 수있는 레코드의 필드 (ref 데이터 구조 포함) 및 명시 적으로 변경 가능으로 표시된 개체의 필드뿐입니다.

2

난 당신이 느슨하게 여기에 수정 단어를 사용하는 생각 그리고 그건 당신에게 잘못이 아니야. 나는 거기에있는 사람들이 재귀 적 데이터 구조에서 참조를 사용할 것이라고 의심한다. 그리고 새로운 것이기 때문에, 당신이 문자 적으로 그런 의미로 사용한다는 것을 정당화하는 것이 어렵습니다.

기능적 언어에서 우리는 일반적으로 불변의 데이터 구조를 다루기 때문에 차이가 있습니다. 여러분이 물어보아야 할 것은 특정 태그가 다른 구조체로 대체 된 새로운 구조체를 반환하는 방법입니다. Pedantry는 제쳐두고, 기능적 언어로하는 것은 매우 자연스러운 일이며, 거의 고려하지 않는 것입니다.

작업하려는 구조를 완전히 정의하십시오. 추가로 태그를 정의했습니다. - 문자열이라고 가정합니다.

type tag = string 
type xml = Element of tag * xml list | CharData of string;; 

그리고 함수의 서명은

val replace_tag : string -> string -> xml -> xml 

let rec replace_tag from_tag to_tag = function 
    (* nothing to do here... *) 
    | (CharData _) as x -> x 
    (* an element with the proper tag; call function on its contents *) 
    | Element (tag, xmlist) when tag = tag_from -> 
     let xmlist = List.map (fun t -> replace_tag from_tag to_tag t) xmlist in 
     let ntag,ncontent = f tag xmlist in 
     Element (tag_to,xmlist) 
    (* look into each element of xml contents *) 
    | Element (tag, xmlist) -> 
     let xmlist = List.map (fun t -> replace_tag from_tag to_tag t) xmlist in 
     Element(tag,xmlist) 

이 내가 당신의 문제가 생각에 괜찮은, 간단한 해결책은, (그래서 우리는 우리가 달성하려고하는 무엇에 분명하다). 이것에는 많은 문제가 있습니다. 값이 존재하지 않으면 오류 검사를 수행하지 않고 매번 List.map 호출로 전체 데이터 구조를 복사합니다.좀 더 자세한 내용을 통해 우리는 당신에게 더 나은 솔루션을 제공 할 수 있다고 생각합니다.

관련 문제