The STREAM_IO 시그니처

The STREAM_IO 시그니처

STREAM_IO 시그니처는 함수형 스트림 기반의 버퍼링된 입력·출력 인터페이스를 정의해요.

출처: 문서

본문

시놉시스 (Synopsis)

signature STREAM_IO

인터페이스 (Interface)

type elem
type vector
type instream
type outstream
type out_pos
type reader
type writer
type pos
val input : instream -> vector * instream
val input1 : instream -> (elem * instream) option
val inputN : instream * int -> vector * instream
val inputAll : instream -> vector * instream
val canInput : instream * int -> int option
val closeIn : instream -> unit
val endOfStream : instream -> bool
val output : outstream * vector -> unit
val output1 : outstream * elem -> unit
val flushOut : outstream -> unit
val closeOut : outstream -> unit
val mkInstream : reader * vector -> instream
val getReader : instream -> reader * vector
val filePosIn : instream -> pos
val setBufferMode : outstream * IO.buffer_mode -> unit
val getBufferMode : outstream -> IO.buffer_mode
val mkOutstream : writer * IO.buffer_mode -> outstream
val getWriter : outstream -> writer * IO.buffer_mode
val getPosOut : outstream -> out_pos
val setPosOut : out_pos -> outstream
val filePosOut : out_pos -> pos

설명 (Description)

type elem
type vector

createIn·createOut은 리더·라이터에서 스트림을 만들어요.

type instream

input은 입력 스트림에서 읽고 새 스트림 상태와 함께 요소를 돌려줘요.

type outstream

output·outputSubstr은 스트림에 써요.

type out_pos

closeIn·closeOut은 스트림을 닫아요.

type reader
type writer

endOfStream은 입력이 끝났는지 알려줘요.

type pos

입력·출력 위치를 조회·설정하는 함수를 담아요.

input f

canInput은 비차단 입력 가능 여부를 알려줘요.

input1 f

스트림 f의 다음 요소와 스트림의 나머지를 돌려줘요. 스트림이 끝에 있으면 NONE을 돌려줘요. 이 조건 중 하나가 충족될 때까지 차단할 수 있어요. 기본 판독기에 오류가 있으면 Io 예외를 발생시켜요.

inputN (f, n)

f에서 다음 n개 요소의 벡터와 스트림의 나머지를 돌려줘요. 다음 스트림 끝 이전에 n개보다 적은 요소가 있으면 그 스트림 끝까지의 모든 요소를 돌려줘요. 추가 문자가 있는지 또는 스트림 끝 조건이 성립하는지 확인할 수 있을 때까지 차단할 수 있어요. 기본 판독기에 오류가 있으면 Io 예외를 발생시켜요. n < 0이거나 반환될 요소 수가 maxLen보다 크면 Size를 발생시켜요. 또한 inputN(f,0)은 빈 벡터와 f를 즉시 반환하므로 스트림 끝의 표시로 사용할 수 없어요. instream을 사용하면 이전 canInput 호출이 SOME(_)을 반환했다면 inputN이 차단하지 않음이 보장되므로 inputN과 canInput으로 inputN의 비차단 버전을 합성할 수 있어요.

inputAll f

스트림 f의 나머지 요소(즉 스트림 끝까지)의 벡터와 새 스트림 f'를 돌려줘요. 인터랙티브 스트림에서는 무한정 차단될 수 있으므로 이 함수를 사용할 때 주의해야 해요. 기본 판독기에 오류가 있으면 Io 예외를 발생시켜요. 스트림 f'는 f의 다음 스트림 끝 직후에 있어요. 스트림 끝이 하나만 예상되는 일반 파일에서는 f'를 무시할 수 있어요. 파일에 여러 스트림 끝 조건이 있으면(일부 운영체제에서 발생할 수 있음) inputAll은 다음 스트림 끝까지의 모든 요소를 돌려줘요. 반환될 요소 수가 해당 벡터 타입의 maxLen보다 크면 Size를 발생시켜요.

canInput (f, n)

어떤 입력 시도라도 차단되면 NONE을 돌려줘요. input 호출이 즉시 최소 k개 문자와 함께 반환되면 0 <= k <= n인 SOME(k)을 돌려줘요. k = 0은 스트림이 스트림 끝에 있음을 나타낸다는 점에 유의하세요. 일부 스트림은 이 연산을 지원하지 않을 수 있는데, 그 경우 Io 예외가 발생해요. 기본 판독기에 오류가 있어도 Io 예외를 발생시켜요. n < 0이면 Size 예외를 발생시켜요. 구현 참고: canInput의 구현은 가능한 한 큰 k를 반환하려고 시도하는 것이 좋아요. 예를 들어 버퍼에 10개의 문자가 있고 사용자가 canInput (f, 15)를 호출하면 canInput은 readVecNB(5)를 호출해 추가 5개의 문자를 사용할 수 있는지 확인해야 해요. 그러한 선행 읽기는 스트림이 readVecNB로 읽은 문자를 커밋하지만, 다음 input 호출에서 그 문자를 반환하도록 스트림을 커밋하지는 않아요. 실제로 일반적인 구현은 input이 호출되면 이 경우 10개의 문자로 구성된 현재 버퍼의 나머지를 단순히 반환해요. 반면에 구현은 이전 input 호출이 스트림을 특정 응답에 커밋하지 않았다면 항상 현재 이용 가능한 모든 요소로 input에 응답하기로 결정할 수 있어요. 유일한 요구는 같은 입력 스트림에 대한 미래의 input 호출이 같은 요소 벡터를 반환해야 한다는 것이에요.

closeIn f

스트림을 닫힘으로 표시하고 기본 판독기를 닫아요. 닫힌 스트림에 closeIn을 적용해도 효과가 없어요. 기본 판독기에 오류가 있으면 Io 예외를 발생시켜요.

endOfStream f

f가 스트림 끝 조건을 충족하는지 검사해요. 스트림에 더 이상 입력이 없으면 true를, 그렇지 않으면 false를 돌려줘요. 기본 판독기에 오류가 있으면 Io 예외를 발생시켜요. 이 함수는 더 많은 입력이 있는지 확인할 때 차단할 수 있어요. (length(#1(input f)) = 0)과 동등해요. 여기서 length는 벡터 길이 연산이에요. endOfStream이 true를 돌려줘도 더 많은 데이터가 이용 가능해지면 이후 입력 연산이 성공할 수 있다는 점에 유의하세요. 스트림은 정상 요소 사이에 여러 스트림 끝을 가질 수 있어요. 예를 들어 Unix에서 사용자가 터미널 장치에 control-D(#"^D")를 입력한 다음 계속 문자를 입력하면 발생할 수 있고, 소켓에 연결된 파일 디스크립터에서도 발생할 수 있어요. 여러 스트림 끝은 기본 판독기의 속성이에요. 따라서 판독기의 readVec은 빈 문자열을 반환한 다음 같은 판독기의 다른 readVec 호출이 비어 있지 않은 문자열을 반환하고, 세 번째 호출이 빈 문자열을 반환할 수 있어요. 그러나 endOfStream f = endOfStream f는 항상 참이에요. 또한 endOfStream f가 true를 돌려주면 input f는 ("",f')를 돌려주고 endOfStream f'는 참일 수도 있고 아닐 수도 있어요.

(length(#1(input f)) = 0)
endOfStream f = endOfStream f

output (f, vec)

요소 벡터 vec를 스트림 f에 써요. f가 종료되었으면 Io 예외를 발생시켜요. 기본 기록기에 오류가 있어도 Io 예외를 발생시켜요.

output1 (f, el)

요소 el을 스트림 f에 써요. f가 종료되었으면 Io 예외를 발생시켜요. 기본 기록기에 오류가 있어도 Io 예외를 발생시켜요.

flushOut f

f의 버퍼에 있는 출력을 기본 기록기로 비워요. 종료된 스트림에서는 no-op이에요. 기본 기록기에 오류가 있으면 Io 예외를 발생시켜요.

closeOut f

f의 버퍼를 비우고 스트림을 닫힘으로 표시하며 기본 기록기를 닫아요. 이 연산은 f가 이미 닫혀 있으면 효과가 없어요. f가 종료되었으면 버퍼 비우기가 발생하지 않는다는 점에 유의하세요. 기본 기록기에 오류가 있거나 버퍼 비우기가 실패하면 Io 예외를 발생시켜요. 후자의 경우 스트림은 열린 상태로 남아요.

mkInstream (rd, v)

판독기 rd 위에 초기 버퍼 내용 v로 새 instream을 만들어요. 판독기가 모든 필드를 구현하지 않으면(예: 임의 접근 연산이 없는 경우) 어떤 연산은 결과 instream에 적용될 때 예외를 발생시켜요. 다음 표는 instream 연산과 판독기 사이의 최소 관계를 설명해요: instream 지원: 판독기가 구현할 때: input, inputN 등 readVec, canInput readVecNB, endOfStream readVec, filePosIn getPos와 setPos. 판독기가 더 많은 연산을 제공하면 결과 스트림이 이를 사용할 수 있어요. mkInstream은 제공된 판독기를 사용해 입력 스트림을 구성해야 해요. 사용자가 판독기의 합성 함수를 사용하려면 augmentReader(rd)로 확장된 판독기로 mkInstream을 호출할 수 있어요. augmentReader가 생성하는 함수에 대한 설명은 PRIM_IO를 참조하세요. 판독기는 명령형 객체이므로 단일 판독기 위에 둘 이상의 입력 스트림을 구축하면 예측할 수 없는 효과가 발생해요. 일반적으로 판독기와 입력 스트림 시퀀스 사이에는 1-1 대응이 있어야 해요. 또한 이런 방식으로 입력 스트림을 만들면 스트림이 실제로 읽으려고 시도할 때까지 판독기가 닫혔다는 것을 인지하지 못할 수 있다는 점에 유의하세요.

getReader f

입력 스트림 f를 잘림으로 표시하고 기본 판독기와 버퍼에서 소비되지 않은 데이터를 함께 돌려줘요. 반환된 데이터는 (closeIn f; inputAll f) 값을 가져요. f가 닫혔거나 잘렸으면 Io 예외를 발생시켜요.

filePosIn f

버퍼링된 스트림 f에서 다음에 읽을 요소에 해당하는 기본 수준의 판독기 위치를 돌려줘요. 스트림이 이 연산을 지원하지 않거나 f가 잘렸으면 Io 예외를 발생시켜요. 모든 연산이 정의되고 종료된다고 가정할 때, #1(inputAll f)가 벡터 v를 반환하면 (setPos (filePosIn f); readVec (length v))도 v를 반환해야 해요. 구현 참고: pos 타입이 바이트 오프셋에 해당하는 구체적인 정수이고 (바이트와 요소 사이의) 변환 함수가 알려져 있으면 값을 직접 계산할 수 있어요. 그렇지 않으면 값은 아래와 같은 fun pos 함수로 주어져요. 여기서 bufp는 현재 버퍼 시작에 해당하는 파일 위치, n은 현재 버퍼에서 이미 읽은 요소 수, r은 스트림의 기본 판독기예요.

(setPos (filePosIn f); readVec (length v))
fun pos (bufp, n, r as RD rdr) = let
val readVec = valOf (#readVec rdr)
val getPos = valOf (#getPos rdr)
val setPos = valOf (#setPos rdr)
val savep = getPos()
in
setPos bufp;
readVec n;
getPos () before setPos savep
end

setBufferMode (f, mode)

getBufferMode f

이 함수들은 출력 스트림 f의 버퍼링 모드를 설정하고 가져와요. 버퍼 모드를 IO.NO_BUF로 설정하면 버퍼링된 출력이 비워져요. 버퍼 비우기가 실패하면 Io 예외가 발생해요. IO.LINE_BUF와 IO.BLOCK_BUF 사이를 전환해도 버퍼 비우기가 발생해서는 안 돼요. IO.BLOCK_BUF에서 IO.LINE_BUF로 갈 때 사용자가 버퍼에 줄바꿈 문자가 없길 원한다면 flushOut을 명시적으로 호출해야 해요.

mkOutstream (wr, mode)

기록기 wr 위에 지정된 버퍼 모드로 새 출력 스트림을 만들어요. 기록기가 모든 필드를 구현하지 않으면(예: 임의 접근 연산이 없는 경우) 어떤 연산은 결과 outstream에 적용될 때 예외를 발생시켜요. 다음 표는 outstream 연산과 기록기 사이의 최소 관계를 설명해요: outstream 지원: 확장된 기록기가 구현할 때: output, output1 등 writeArr, flushOut writeArr, setBufferMode writeArr, getPosOut writeArr와 getPos, setPosOut writeArr와 setPos. 기록기가 더 많은 연산을 제공하면 결과 스트림이 이를 사용할 수 있어요. mkOutstream은 제공된 기록기를 사용해 출력 스트림을 구성해야 해요. 사용자가 기록기의 합성 함수를 사용하려면 augmentWriter(wr)로 확장된 기록기로 mkOutstream을 호출할 수 있어요. augmentWriter가 생성하는 함수에 대한 설명은 PRIM_IO를 참조하세요. 버퍼링이 출력 순서를 바꿀 수 있으므로 단일 기록기 위에 둘 이상의 outstream을 구축하면 예측할 수 없는 효과가 발생해요. 일반적으로 기록기와 출력 스트림 사이에는 1-1 대응이 있어야 해요. 또한 이런 방식으로 출력 스트림을 만들면 스트림이 실제로 쓰려고 시도할 때까지 기록기가 닫혔다는 것을 인지하지 못할 수 있다는 점에 유의하세요.

getWriter f

스트림 f를 비우고 종료됨으로 표시하며 기본 기록기와 스트림의 버퍼 모드를 반환해요. f가 닫혔거나 버퍼 비우기가 실패하면 Io 예외를 발생시켜요.

getPosOut f

스트림 f의 현재 위치를 돌려줘요. 스트림이 이 연산을 지원하지 않거나, 어떤 암시적 버퍼 비우기가 실패하거나, f가 종료되었으면 Io 예외를 발생시켜요. 구현 참고: 이 함수의 일반적인 구현은 pos 타입의 값을 계산해야 하며, f에 다음에 쓸 요소가 기본 파일의 어디에 쓰일지 포착해요. pos 타입이 바이트 오프셋에 해당하는 구체적인 정수이고 (바이트와 요소 사이의) 변환 함수가 알려져 있으면 getPos를 사용해 값을 직접 계산할 수 있어요. 그렇지 않으면 값은 아래와 같은 fun pos 함수로 주어져요. 여기서 f는 출력 스트림이고 w는 스트림의 기본 기록기예요.

fun pos (f, w as WR wtr) = let
val getPos = valOf (#getPos wtr)
in
flushOut f;
getPos ()
end

setPosOut opos

opos의 기본 스트림의 출력 버퍼를 비우고, opos에 기록된 위치로 스트림의 현재 위치를 설정하며, 스트림을 반환해요. 버퍼 비우기가 실패하거나, 스트림이 이 연산을 지원하지 않거나, opos의 기본 스트림이 종료되었으면 Io 예외를 발생시킬 수 있어요.

filePosOut opos

추상 출력 스트림 위치 opos에 해당하는 기본 수준의 기록기 위치를 돌려줘요. 출력 스트림 f와 요소 벡터 v가 주어지고 opos가 getPosOut(f)와 같다고 하자. 그러면 모든 연산이 정의되고 종료된다고 가정하고 writeVec 호출이 length v를 반환한다고 할 때, 코드 (setPos opos; writeVec{buf=v,i=0,sz=NONE})는 (f,v)로 호출된 아래 fun put 함수의 마지막 줄과 같은 효과를 가져야 해요.

(setPos opos; writeVec{buf=v,i=0,sz=NONE})
fun put (outs,x) = (flushOut outs;
output(outs,x);flushOut outs)
```## 더 알아보기 (Learn more)

-