윤형석
가입: 2012년 9월 5일 올린 글: 26
|
올려짐: 2012년11월13일 15:45 주제: 숙제 6-1에서 두 종류의 module간의 타입 충돌에 대한 질문입니다. |
|
|
작년 게시판을 보다보니, 다음과 같은 글이 있었습니다.
https://ropas.snu.ac.kr/phpbb/viewtopic.php?t=2997
인용: | 이번 숙제에서 Sm5와 Sonata라는 두 모듈을 사용하는데 실제 이 두 모듈 내부의 type 정의들은 거의 일치합니다.
그러다보니 Sm5의 PUSH obj 명령어의 obj를 바로 Sonata에 집어넣으면 type error가 발생합니다. 실제로는 Sm5.obj와 Sonata.obj의 내부 구조는 똑같은데 말이죠.
1.
Ocaml 메뉴얼을 찾아보니 이런 경우 "with type" 이라는 형식을 이용한 sharing constraints를 통해 두 타입을 같다고 지정할 수 있다고 합니다. 하지만 예제 코드를 보면 이런 정의가 타입이 있는 모듈 내에서 이뤄지기 때문에 hw6_1.ml만 제출해야 하는 이번 숙제에서는 사용하기 힘든 것 같습니다. 두 모듈을 open으로 불러들인 후 두 모듈간에 sharing constraints를 지정해 줄 수 있는 방법이 있나요?
2. 처음에는 그냥 저 문제를 회피(?)하고 내부로 파고들어 일일히 선언을 해줄려고 했었는데 역시 문제가 생겼습니다.
| (Sm5.PUSH (Sm5.Val (Sm5.L (i1, i2)))) :: rest ->
(Sonata.PUSH (Sonata.Val (Sonata.L (i1, i2)))) :: (rozetta rest)
Error: This pattern matches values of type 'a * 'b
but a pattern was expected which matches values of type Sm5.Sm5.loc
두 모듈 모두 type loc = (int * int)로 정의되어있는데도 불구하고 저런 에러가 발생하는 이유에 대해 질문을 드립니다. loc이라는 타입이 양 모듈의 sig에서는 선언만 되어 있고 definition은 struct 속에 들어가 있기 때문에 hw6_1.ml에서는 접근할 수 없어서 에러가 발생하는 것인가요?
|
여기에 이 때 당시의 조교님이 답변을 다음과 같이 달아뒀는데, 이 답변 그대로 받아들여도 될까 싶어 질문을 드립니다.
인용: | 이 부분을 어떻게 해야할까 고민을 많이 해보았습니다.
분명 Sm5의 정의에 따르면 cmd를 이용해서 직접 Loc이나 Record를 push할 수 있습니다.
하지만 그게 일반적인, 제대로 된 Sm5 프로그래밍 방법은 아닐것입니다.
Loc은 malloc을 이용해 할당받은것을 이용해야합니다.
그렇지 않은 주소를 직접 이용하면 메모리 구현에 따라 에러가 발생할 수 있겠죠.
마치 C에서 보통 주소값을
코드: |
int *p = malloc(16);
int *q = &i;
|
이런식으로 쓰는것이 정상적인 방법이지만
코드: |
int *p=(int *)0x08048576;
|
이렇게 쓰는것도 허용하는 것처럼요. 하지만 이런 식의 주소값은
그 프로그램이 얹혀 돌고있는 기계와 운영체제를 확실히 꿰고있을 때에만
매우 제한적으로 쓰입니다.
Sm5의 모듈타입에서 loc과 record의 타입을 숨기고있는것도 그런 상황을 반영합니다.
실제로 K -> SM5 인터프리터를 작성하실때는 그런 고민을 하지 않으셨을겁니다.
malloc과 box, unbox만으로 필요한 모든것을 표현할 수 있으니까요.
그래서 다음과 같이 결정했습니다.
1. Sm5 모듈은 기존에 드린 뼈대 그대로입니다.
loc 값과 record 값이 어떻게 생겼는지 알 수 없기 때문에,
그런 입력은 들어오지 않는다고 가정하겠습니다.
입력으로 들어온 Sm5 프로그램이 loc이나 record 상수를 push하려 시도하면
코드: |
raise (Invalid_argument "rozetta")
|
예외를 발생시켜주세요.
예를 들어,
코드: |
Sm5.PUSH(Sm5.Val(Sm5.L location))
Sm5.PUSH(Sm5.Val(Sm5.R record))
|
이런 명령들은 입력으로 들어오지 않습니다.
물론 이는 push v::C 의 경우에만 해당됩니다.
push x::C로 이미 환경에 저장되어있던 무언가를 꺼내오는 것에는 해당되지 않습니다.
2. Sonata 모듈의 경우 모듈 타입에 loc = int * int 라는 부분을 추가하겠습니다.
Sm5 프로그램을 Sonata 프로그램으로 인코딩하는 과정에서
미리 고정된 loc 값이 필요하다면 쓰실 수 있습니다.
sonata.ml 파일의
코드: |
module type SONATA =
sig
...
and loc
...
end
|
이 부분을
코드: |
module type SONATA =
sig
...
and loc = int * int
...
end
|
이렇게 고쳐서 쓰세요.
뼈대도 이렇게 고쳐서 다시 올려드리겠습니다.
단, record는 여전히 가려져있습니다.
어떤 record 값을 만들어야한다면 push와 box 명령을 이용하세요.
|
|
|