1. Topaz 문서에 오신 것을 환영합니다!
이 문서는 극강의 효율성, 모호함 없는 명확성, 그리고 원활한 AI 통합을 위해 설계된 획기적인 언어, Topaz의 공식 가이드입니다. 개발자 친화적인 루비(Ruby)의 철학에서 영감을 받고, 신선한 LISP과 유사한 S-표현식 구문으로 구축된 Topaz는 빠르게 발전하는 기술의 세계에서 신입 개발자와 숙련된 개발자 모두에게 강력한 힘을 실어주도록 설계되었습니다.
Topaz란 무엇인가요?
Topaz(Core Syntax Language, 또는 CSL로도 알려짐)는 단순한 프로그래밍 언어를 넘어, 미래 지향적인 생태계입니다. 특히 AI 기반 애플리케이션, 임베디드 시스템, 로보틱스 분야에서 개발자 생산성을 재정의하는 것을 목표로 합니다.
미니멀하고 기계 친화적인 S-표현식 구문과 강력한 타입 추론을 지원하는 강력한 정적 타이핑을 우선시함으로써, Topaz는 여러분의 코드가 간결하고 우아할 뿐만 아니라, 견고하고 예측 가능하며 높은 성능을 보장합니다.
예제: 당신의 첫 Topaz 프로그램
Topaz가 고전적인 "Hello, World!"를 어떻게 처리하는지 살펴봅시다:
;; main.tpz - 간단한 "Hello, World!" Topaz 프로그램
;; 콘솔에 출력하는 main 프로세스(함수)를 정의합니다.
;; Topaz는 S-표현식을 사용합니다: (연산자 인자1 인자2 ...)
;; $는 정의에 사용됩니다. λ는 익명 프로세스를 생성합니다.
($ main
(λ () ;; 인자를 받지 않는 프로세스
(io:print "Hello, Topaz World!") ;; io 모듈의 print 함수
)
)
;; main 프로세스를 실행하려면 (Topaz 런타임 환경에 따라 'main' 프로세스는
;; 암시적으로 실행되거나 명시적으로 호출될 수 있습니다):
;; (main)
이 예제는 프로세스를 정의(λ
)하고 연산을 호출(io:print
)하는 Topaz의 S-표현식 구문을 보여줍니다. 이 코드 블록을 렌더링하는 CodeBlock
컴포넌트는 곧 완벽한 Topaz 구문 강조 기능을 선보일 예정입니다!
Topaz의 주요 강점
- AI 중심 설계: AI 처리, 생성, 협업에 최적화되도록 처음부터 설계되었습니다.
- 강력한 S-표현식 구문: 일단 익숙해지면, 인간과 기계 모두에게 뛰어난 메타프로그래밍 기능, 구조적 명확성, 그리고 파싱의 용이성을 제공합니다.
- 극강의 효율성과 성능: 속도, 최소한의 오버헤드, 그리고 자원이 제한된 환경에 최적화되어 있습니다.
- 모호함 없고 명시적인 구조: 인지 부하를 줄이고, 부작용을 최소화하며, 일반적인 프로그래밍 오류를 방지하도록 설계되었습니다.
- 루비에서 영감을 받은 철학: 독특한 구문 체계 안에서 개발자의 행복과 표현력을 중시합니다.
다음 단계
더 깊이 알아볼 준비가 되셨나요?
- 시작하기 가이드로 기본을 배우고 개발 환경을 설정하며 여정을 시작하세요 (또는 곧 출시될 온라인 플레이그라운드를 기대해주세요!).
- Topaz 구문, 데이터 구조, 핵심 개념에 대한 깊이 있는 이해를 위해 언어 참조를 탐색해보세요.
- 코어 신택스 커널(Core Syntax Kernel)의 전체적인 비전과 그 안에서 Topaz가 맡은 핵심적인 역할을 확인해 보세요.
여러분이 Topaz를 탐험하게 되어 매우 기쁩니다. 프로그래밍의 새로운 명확성과 강력함의 시대에 오신 것을 환영합니다!
2. Topaz 시작하기
환영합니다! 이 가이드는 Topaz 개발 환경 설정(사용 가능해지면), 첫 Topaz 프로그램 작성, 그리고 기본적인 프로젝트 구조 이해를 안내합니다. 최대한 원활하게 시작하고 실행할 수 있도록 돕는 것이 우리의 목표입니다.
설치
(Topaz 언어와 툴체인은 현재 활발히 개발 중입니다. 이 섹션은 첫 공식 SDK(소프트웨어 개발 키트)가 출시되면 자세한 설치 지침으로 업데이트될 예정입니다. 설치 방법으로는 패키지 매니저, 다운로드 가능한 바이너리, 또는 소스에서 직접 빌드하는 방법 등이 포함될 수 있습니다.)
설치 예시 (향후 채워질 내용):
다음과 같은 명령어를 사용하여 Topaz를 설치할 수 있습니다:
# 가상 패키지 매니저 사용 예시
# $ cool_package_manager install topaz-sdk
# 또는 바이너리를 다운로드하여 설정하는 예시
# $ wget [https://topaz.ooo/downloads/topaz-sdk-v0.1.0.tar.gz](https://topaz.ooo/downloads/topaz-sdk-v0.1.0.tar.gz)
# $ tar -xzf topaz-sdk-v0.1.0.tar.gz
# $ export PATH=$(pwd)/topaz-sdk/bin:$PATH
공식 설치 지침을 다시 확인해주세요.
당신의 첫 Topaz 프로그램: "Hello, Topaz!"
전통적인 "Hello, World!" 프로그램을 Topaz 스타일로 만들어 봅시다.
hello.tpz
라는 새 파일을 만듭니다.- 선호하는 텍스트 편집기에서 파일을 열고 다음 Topaz 코드를 입력합니다:
;; hello.tpz
;; Topaz의 세계로 떠나는 당신의 첫 모험!
;; Topaz에서 연산은 일반적으로 (연산자 인자1 인자2 ...) 형식으로 작성됩니다.
;; io:print는 콘솔에 텍스트를 출력하는 io 모듈의 함수입니다.
(io:print "Hello from Topaz!")
이 간단한 코드 한 줄은 Topaz에게 "Hello from Topaz!"라는 문자열을 콘솔에 출력하라고 지시합니다.
프로그램 실행하기:
(Topaz 프로그램을 컴파일(필요 시)하고 실행하는 정확한 명령어는 공식 툴체인과 함께 제공될 예정입니다. 지금은 hello.tpz
파일을 실행하기 위해 다음과 같은 명령어를 상상해보세요.)
가상 실행 예시:
# 이 명령어는 Topaz 런타임이나 인터프리터에 따라 달라집니다
topaz run hello.tpz
성공적으로 실행되면 다음과 같은 출력을 보게 될 것입니다:
Hello from Topaz!
축하합니다! 방금 첫 Topaz 프로그램을 실행했습니다.
기본 프로젝트 구조 (개념적)
프로젝트가 커짐에 따라 파일을 정리하고 싶을 것입니다. 공식 프로젝트 구조와 빌드 도구는 아직 확정되지 않았지만, 일반적인 Topaz 프로젝트는 다음과 유사한 구조를 채택할 수 있습니다:
my_topaz_project/
├── src/ # 소스 파일
│ ├── main.tpz # 애플리케이션의 주 진입점
│ └── lib/ # 재사용 가능한 라이브러리 코드 또는 모듈
│ └── utils.tpz # 유틸리티 모듈 예시
├── topaz_project.toml # (가상) 프로젝트 명세 파일: 의존성, 설정 등
├── .gitignore # Git 무시 파일
└── README.md # 프로젝트 설명
src/
: 이 디렉토리는 모든 Topaz 소스 코드(.tpz
파일)를 포함합니다.topaz_project.toml
(또는 유사한 파일): 미래에 추가될 명세 파일로, Rust의Cargo.toml
이나 Node.js의package.json
처럼 프로젝트 메타데이터, 의존성, 빌드 설정 등을 정의할 수 있습니다.
(Topaz 생태계의 이러한 구성 요소들이 성숙함에 따라 공식 프로젝트 명세 형식, 모듈 정의 및 연결 방법, 빌드 시스템에 대한 자세한 내용이 제공될 예정입니다.)
다음 단계
이제 Topaz를 처음 맛보았으니, 더 깊이 탐험할 준비가 되었습니다:
- 핵심 구문, 데이터 타입, 연산을 이해하려면 상세한 언어 참조를 살펴보세요.
- 일반적인 프로그래밍 작업과 Topaz 고유 패턴에 대한 튜토리얼은 실용 가이드를 확인하세요.
- (곧) 곧 출시될 온라인 플레이그라운드에서 Topaz를 직접 실험해보세요!
여러분이 Topaz로 무엇을 만들지 기대됩니다!
3. Topaz를 위한 실용 가이드
이 섹션은 Topaz 언어를 사용하여 일반적인 작업을 수행하는 데 도움이 되는 실용적인 가이드와 튜토리얼 모음을 제공합니다. 이 가이드들은 여러분이 시작하기와 언어 참조 섹션에서 다룬 Topaz의 기본 구문과 개념을 이해하고 있다고 가정합니다.
코드 예제를 직접 실험해보시길 권장합니다. 이 블록들에서 Topaz에 대한 완전한 구문 강조는 곧 지원될 예정이지만, S-표현식 구조는 명확하게 보일 것입니다.
모듈 작업하기
Topaz에서 모듈성은 대규모 프로젝트를 구성하고 코드 재사용성을 높이는 핵심입니다. 패키지, 네임스페이스, 세분화된 가져오기/내보내기 제어를 정의하는 정밀한 상위 레벨 모듈 시스템은 활발히 개발 중인 영역이며 향후 업데이트에서 상세히 설명될 것이지만, 다른 파일의 정의를 사용하는 핵심 개념은 설명할 수 있습니다.
개념적으로, 각 .tpz
파일은 하나의 모듈로 생각할 수 있습니다. 파일의 최상위 레벨에서 만들어진 정의(함수나 상수 등)는 링킹 프로세스나 미래의 가져오기 메커니즘을 통해 다른 파일에서 접근할 수 있게 됩니다.
(이 가이드는 한 파일에서 재사용 가능한 함수를 정의하고 다른 파일에서 사용하는 방법을 안내할 것입니다. 진화하는 모듈 시스템에 대한 예제 코드와 설명은 확정되는 대로 여기에 제공될 것입니다.)
예시:
utils.tpz
라는 유틸리티 파일이 있다고 가정해봅시다:
;; 파일: src/utils.tpz
;; 간단한 유틸리티 모듈.
(MODULE utils
(EXPORT add greet)
;; 'a'와 'b' 두 인자를 받는 'add' 프로세스를 정의합니다.
($ add
(λ (a b)
(+ a b) ;; '+'는 핵심 연산입니다
)
)
;; 또 다른 유틸리티
($ greet
(λ (name)
(string:concat "Hello, " name "!") ;; 문자열 결합을 위한 string:concat
)
)
)
그리고 add
함수를 사용하고 싶은 main.tpz
파일이 있습니다:
;; 파일: src/main.tpz
;; 다른 모듈의 함수를 사용하는 것을 보여줍니다.
;; utils 모듈을 u 라는 별칭으로 가져옵니다
(IMPORT utils :as u)
($ main
(λ ()
($ result (u:add 5 3))
(io:print
(string:concat "5 + 3 = " (core:to-string result))
)
)
)
;; (main) ;; main 프로세스를 실행하려면
이는 재사용 가능한 코드를 구조화하고 사용하는 방법을 보여줍니다. Topaz의 모듈 시스템에 대한 자세한 사양을 기대해주세요! 표준 라이브러리 사용법도 핵심 라이브러리 모듈이 정의되면 광범위하게 다룰 것입니다.
파일 I/O
Topaz는 파일 시스템과 상호 작용하기 위한 견고하고 직관적인 연산을 제공할 것입니다. 이는 CLI 도구부터 데이터 처리 파이프라인에 이르기까지 광범위한 애플리케이션에 매우 중요합니다.
(이 가이드는 Topaz의 오류 처리 메커니즘을 사용하여 파일에서 읽기(텍스트, 바이너리), 파일에 쓰기, 파일 존재 여부 확인, 디렉토리 조작, 그리고 잠재적인 I/O 오류 처리를 다룰 것입니다. 예제 코드와 모범 사례가 제공될 예정입니다.)
개념적 예시:
;; 파일에서 텍스트 읽기
($ file-path "data/input.txt")
($ content-result (io:read-text-file file-path)) ;; 연산은 Result 타입을 반환합니다
;; Result 타입 처리와 함께 IF 사용하기
(IF (result:is-ok content-result)
(io:print (string:concat "파일 내용: " (result:get-value content-result)))
(io:print (string:concat "파일 읽기 오류: " (result:get-error content-result)))
)
;; 파일에 텍스트 쓰기
($ output-path "data/output.txt")
($ write-status (io:write-text-file output-path "Hello from Topaz file I/O!"))
(IF (result:is-ok write-status)
(io:print "파일에 성공적으로 썼습니다.")
(io:print "파일 쓰기 오류.")
)
참고: READ-TEXT-FILE
, WRITE-TEXT-FILE
, IS-OK
, GET-VALUE
, GET-ERROR
등은 Topaz의 I/O 및 오류 처리 시스템의 일부가 될 연산 및 결과 처리 함수의 예시적인 이름입니다.
오류 처리
Topaz는 견고한 오류 처리를 염두에 두고 설계되었으며, 많은 경우에 전통적인 예외 처리 방식보다 명시적인 오류 관리를 선호합니다. 이는 명확하고 예측 가능하며 복원력 있는 소프트웨어를 생산하려는 목표와 일치합니다. 주된 메커니즘은 Result/Option 타입 (또는 유사한 대수적 데이터 타입 - ADT)이 될 것입니다.
(이 가이드는 Topaz에서의 오류 처리를 위한 모범 사례를 깊이 파고들 것입니다. Result/Option 타입을 효과적으로 사용하는 방법, 오류를 전파하는 방법, 그리고 실패로부터 우아하게 복구하는 전략을 탐구할 것입니다. 잠재적인 오류 상태를 명확하게 전달하고 처리하는 코드를 작성하는 방법을 배우게 됩니다.)
개념적 예시:
;; 실패할 수 있는 함수, Result 타입을 반환합니다
($ safe-divide
(λ (numerator denominator)
(IF (= denominator 0)
(result:err "0으로 나누기 오류!") ;; 실패를 위한 result:err 생성자
(result:ok (/ numerator denominator)) ;; 성공을 위한 result:ok 생성자
)
)
)
($ operation-result (safe-divide 10 2))
;; ($ operation-result (safe-divide 10 0)) ;; 오류 케이스를 테스트하려면
;; 결과 처리하기
(IF (result:is-ok operation-result)
(io:print (string:concat "결과: " (core:to-string (result:get-value operation-result))))
(io:print (string:concat "오류: " (result:get-error operation-result)))
)
이 예시는 OK
와 ERR
이 Result ADT의 생성자이고, IS-OK
, GET-VALUE
, GET-ERROR
가 이를 다루기 위한 헬퍼 함수/매크로라고 가정합니다.
동시성
Topaz는 **메시지 전달 원칙(액터 모델이나 CSP와 유사)**에 기반한 명확하고 효율적인 동시성 모델을 지원할 것입니다. 이 접근 방식은 공유 상태를 최소화하고, 경쟁 상태 및 교착 상태와 같은 일반적인 동시성 버그를 방지하며, 멀티코어 및 분산 환경에서 효과적으로 확장하기 위해 선택되었습니다.
(이 가이드는 동시성 프로세스(또는 "액터") 생성, 메시지 송수신, 동시성 환경에서의 상태 관리와 같은 Topaz의 동시성 기본 요소를 소개할 것입니다. 반응성 있고 병렬적인 애플리케이션을 구축하기 위한 패턴을 다룰 것입니다.)
개념적 예시 (매우 추상적인 수준의):
;; "작업자" 역할을 하는 프로세스를 정의합니다
($ my-worker-process
(λ (message-channel)
;; 메시지를 받기 위한 루프
(concurrent:loop
($ received-message (concurrent:receive message-channel))
(io:print (string:concat "작업자가 받음: " received-message))
;; ... 어떤 작업을 수행 ...
)
)
)
;; 작업자 생성
($ worker-channel (concurrent:create-channel))
(concurrent:spawn (my-worker-process worker-channel))
;; 작업자에게 메시지 보내기
(concurrent:send worker-channel "작업 A")
이는 매우 예시적입니다. LOOP
, RECEIVE
, CREATE-CHANNEL
, SPAWN
, SEND
의 실제 구문은 동시성 모델 및 표준 라이브러리의 일부로 정의될 것입니다.
간단한 웹 서버 구축하기 (예제 프로젝트)
언어를 배우는 가장 좋은 방법 중 하나는 실용적인 것을 만들어보는 것입니다. 효율성에 중점을 둔 Topaz는 네트워크 애플리케이션에 매우 적합합니다.
(이 가이드는 Topaz로 처음부터, 또는 초기 버전의 표준 네트워킹 라이브러리를 사용하여 기본적인 HTTP 서버를 만드는 단계별 과정을 제공할 것입니다. 요청 처리, 라우팅, 응답 전송에 대해 배우게 됩니다.)
(웹 서버 구축에 대한 자세한 코드 예제와 설명은 Topaz의 네트워킹 기능이 개발됨에 따라 여기에 제공될 것입니다.)
Topaz가 발전함에 따라 더 많은 가이드가 시간이 지남에 따라 추가될 것입니다. 여러분의 피드백과 도움이 될 만한 가이드에 대한 제안을 환영합니다! [커뮤니티 채널(링크 추후 결정)] 또는 [GitHub 저장소(링크 추후 결정)]를 통해 기여해주세요.
4. Topaz 언어 구문
Topaz 공식 구문 참조에 오신 것을 환영합니다! 이 문서는 Topaz 언어를 구성하는 기본적인 문법과 구문 구조에 대한 포괄적인 개요를 제공합니다. Topaz는 모호함 없는 명확성, 극강의 효율성, 그리고 LISP에서 영감을 받은 S-표현식 구조에 중점을 두고 설계되어, 개발자에게는 강력한 도구가 되고 AI 도구 및 애플리케이션에는 매우 적합한 언어입니다.
핵심 구문 철학
세부 사항에 들어가기 전에, 다음 핵심 원칙을 이해하면 Topaz 구문의 본질을 파악하는 데 도움이 됩니다:
- S-표현식 기반: Lisp 및 Scheme의 여러 방언과 마찬가지로, 모든 Topaz 코드는 S-표현식(Symbolic Expressions)으로 작성됩니다. S-표현식은 아톰(숫자나 심볼과 같은 기본 데이터 값)이거나 괄호
()
로 둘러싸인 S-표현식의 리스트입니다. 이 통일된 트리 같은 구조는 파싱을 단순화하고, 언어를 매우 규칙적으로 만들며, 강력한 메타프로그래밍 능력을 가능하게 합니다. - 표현식 중심: Topaz에서는 거의 모든 것이 값으로 평가되는 표현식입니다. 이는 언어의 간결함과 함수형 특성에 기여합니다.
- 미니멀리즘과 일관성: 구문은 언어 전반에 걸쳐 일관되게 적용되는 소수의 핵심 규칙으로 설계되었습니다.
- 강력한 타입 추론을 갖춘 정적 타이핑: Topaz는 안전성과 성능을 위해 정적 타입을 사용하지만, 강력한 타입 추론 시스템 덕분에 명시적인 타입 표기가 종종 필요하지 않습니다. (자세한 내용은 데이터 타입 참조).
- 기본적으로 불변성: 데이터 구조는 기본적으로 불변(immutable)이므로, 특히 동시성 환경에서 더 안전하고 예측 가능한 코드를 장려합니다.
- 함수형 프로그래밍 원칙: Topaz는 순수 함수와 고차 프로세스를 활용하여 함수형 프로그래밍 패러다임을 수용하고 권장합니다.
기본 요소
1. S-표현식
Topaz의 기본 구문 단위입니다.
;; 아톰 (Atoms):
42 ;; 정수 (Integer)
3.14159 ;; 부동 소수점 수 (Floating-point number)
"Hello, Topaz" ;; 문자열 (String)
:my-symbol ;; 심볼 (Symbol)
is-ready? ;; 식별자 (Identifier, 아톰이 될 수도 있음)
#true ;; 불리언 true 리터럴
#false ;; 불리언 false 리터럴
NULL_SIG ;; 특수한 Null 시그널 값
;; 리스트 (Lists, 이 또한 S-표현식입니다):
(+ 10 20) ;; 간단한 연산: 연산자 뒤에 인자들이 옴
($ x 100) ;; 정의: 특수 구문, 식별자, 표현식
(λ (a b) (+ a b)) ;; 람다 (익명 프로세스) 정의
리스트의 첫 번째 요소는 일반적으로 연산자(내장 연산 또는 사용자 정의 프로세스) 또는 특수 구문($
또는 λ
등)입니다. 나머지 요소는 해당 연산자의 인자입니다.
2. 주석
주석은 Topaz 인터프리터/컴파일러에 의해 무시되며, 사람이 읽을 수 있는 설명을 위해 사용됩니다. Topaz는 이중 세미콜론 ;;
을 한 줄 주석으로 사용합니다. ;;
부터 줄 끝까지의 모든 내용은 주석입니다.
;; 이것은 한 줄 전체 주석입니다.
($ pi 3.14159) ;; 이 주석은 같은 줄의 표현식 뒤에 옵니다.
3. 식별자
식별자는 변수, 상수, 프로세스, 매개변수 등에 사용되는 이름입니다. 일반적으로 문자나 일부 허용된 기호로 시작하며, 문자, 숫자 및 일부 특수 문자(예: -
, ?
, !
)를 포함할 수 있습니다. 관례는 스타일 가이드에서 더 자세히 다룰 것입니다.
$ my-variable 10
$ process? (λ (x) (> x 0))
$ update-state! (λ (s) (;;...
))
핵심 구문 형식
다음은 Topaz 프로그램을 구성하는 데 사용되는 주요 구문입니다.
1. 정의: $
$
특수 구문은 표현식의 결과 값을 현재 스코프의 식별자에 바인딩합니다.
구문: ($ 식별자 표현식)
식별자
: 정의할 이름입니다.표현식
: 모든 Topaz 표현식. 이 표현식의 평가 결과가식별자
에 바인딩됩니다.
예시:
($ age 30)
($ message "Welcome to Topaz")
($ sum (+ 15 27)) ;; sum은 42에 바인딩됨
;; 이름 있는 프로세스(함수) 정의하기
($ add-numbers
(λ (x y)
(+ x y)
)
)
2. 연산 (프로세스/함수 호출)
프로세스(사용자 정의 또는 내장)를 호출하는 데는 전위 표기법(prefix notation)을 사용합니다.
구문: (연산자 인자_1 인자_2 ... 인자_N)
연산자
: 프로세스로 평가되는 식별자 또는 내장 연산자 심볼입니다.인자_n
: 연산자가 적용되기 전에 평가되는 표현식입니다.
예시:
(+ 1 2 3) ;; 6으로 평가됨
(CONCAT "Topaz " "is " "fun!") ;; "Topaz is fun!"으로 평가됨
(> 10 5) ;; 불리언 컨텍스트에서 true(1)로 평가됨
;; 위에서 정의한 'add-numbers' 프로세스 사용하기
(add-numbers 100 200) ;; 300으로 평가됨
3. 데이터 리터럴
Topaz는 핵심 데이터 타입에 대한 직접적인 구문 표현을 가지고 있습니다. 포괄적인 가이드는 데이터 타입 페이지를 참조하세요.
- 숫자:
123
,-10
,3.14
,0.0
- 문자열:
"A string"
,""
(빈 문자열) - 불리언:
#true
(참)와#false
(거짓)가 공식 불리언 리터럴입니다.
($ is-enabled #true)
($ has-errors #false)
- 심볼: 콜론(
:
)으로 시작하거나(예::active
,:error-code
) 따옴표로 묶입니다(예:'my-symbol
). 고유한 식별자나 열거형과 유사한 값에 사용됩니다.
($ current-status :pending)
- 벡터 (순서 있는 리스트): 대괄호
[]
로 둘러싸입니다.
($ empty-vec [])
($ primes [2 3 5 7 11])
($ mixed-data [10 "label" :option-a])
- 맵 (키-값 쌍):
(#
로 시작하여 키와 값을 번갈아 나열하고)
로 닫습니다.
($ empty-map (#))
($ point (# :x 10 :y 20))
($ config (# "host" "localhost" "port" 8080 :retries 3))
NULL_SIG
: 값의 부재를 나타내는 특수 리터럴입니다.
($ no-result NULL_SIG)
4. 조건부 분기: IF
IF
특수 구문은 조건부 평가를 제공합니다.
구문: (IF 조건_표현식 참_표현식 거짓_표현식)
조건_표현식
: 평가됩니다.#true
는 조건이 참임을,#false
또는NULL_SIG
는 거짓임을 의미합니다.참_표현식
:조건_표현식
이 참일 경우 평가됩니다.거짓_표현식
:조건_표현식
이 거짓일 경우 평가됩니다. (거짓_표현식
을 생략하면 조건이 거짓일 때NULL_SIG
가 결과가 됩니다).
예시:
($ user-age 25)
($ access-level (IF (>= user-age 18)
:adult
:minor)) ;; access-level은 :adult가 됨
($ temperature 15)
($ weather-advice (IF (< temperature 0)
"아주 따뜻한 코트를 입으세요!"
(IF (< temperature 15)
"가벼운 재킷이면 충분해요."
"쾌적한 날씨를 즐기세요!"
)
))
5. 익명 프로세스 (람다): λ
λ
(람다) 특수 구문은 익명 프로세스(함수)를 생성합니다.
구문: (λ (매개변수_1 ... 매개변수_N) 본문_표현식_1 ... 본문_표현식_N)
(매개변수_1 ... 매개변수_N)
: 매개변수 식별자 목록입니다. 매개변수가 없으면()
를 사용합니다.본문_표현식_n
: 프로세스 본문을 형성하는 하나 이상의 표현식입니다. 마지막 표현식의 값이 반환 값입니다.
예시:
;; 숫자를 제곱하는 프로세스
(λ (n) (* n n))
;; $를 사용하여 람다로 정의된 프로세스에 이름 부여하기
($ square (λ (n) (* n n)))
(square 7) ;; 49로 평가됨
($ create-greeter
(λ (greeting)
(λ (name) (string:concat greeting ", " name "!"))
)
)
($ hello-greeter (create-greeter "Hello"))
(hello-greeter "Topaz Developer") ;; "Hello, Topaz Developer!"로 평가됨
6. 사용자 정의 타입: DEFINE-TYPE
DEFINE-TYPE
특수 구문은 구조화된 데이터 타입(struct나 record와 유사)을 생성합니다.
구문: (DEFINE-TYPE 타입이름 (# :필드이름1 필드타입1 :필드이름2 필드타입2 ...))
예시:
;; x와 y 좌표를 갖는 Point 타입 정의
(DEFINE-TYPE Point (# :x Float :y Float))
;; 타입 구조와 일치하는 맵 리터럴을 사용하여 인스턴스 생성
($ origin (# :x 0.0 :y 0.0))
($ point1 (# :x 10.5 :y -5.0))
;; 여러 필드 타입을 갖는 Person 타입 정의
(DEFINE-TYPE Person (# :name String :age Integer :active Boolean))
($ user (# :name "Alice" :age 30 :active #true))
7. 열거형 타입: DEFINE-ENUM
DEFINE-ENUM
특수 구문은 고정된 심볼 값 집합을 갖는 열거형 타입을 생성합니다.
구문: (DEFINE-ENUM 열거형이름 :값1 :값2 :값3 ...)
예시:
;; 색상 열거형 정의
(DEFINE-ENUM Color :RED :GREEN :BLUE)
;; 상태 열거형 정의
(DEFINE-ENUM Status :PENDING :COMPLETED :FAILED :CANCELLED)
;; 열거형 값 사용
($ my-color :RED)
($ task-status :PENDING)
8. 제네릭 타입 (타입 매개변수): λ [TypeParams]
제네릭 프로세스는 타입 매개변수를 선언하여 여러 타입과 함께 작동할 수 있습니다.
구문: (λ [타입매개변수1 타입매개변수2 ...] (매개변수1: 타입1 매개변수2: 타입2 ...) 본문-표현식 ...)
예시:
;; 모든 타입 T와 함께 작동하는 제네릭 항등 함수
($ identity
(λ [T] (value: T)
value
)
)
;; 벡터의 첫 번째 요소를 가져오는 제네릭 함수
($ first-element
(λ [E] (vec: (Vector E))
(vector:first vec)
)
)
;; 제네릭 함수 사용
($ num-result (identity 42)) ;; T는 Integer로 추론됨
($ str-result (identity "hello")) ;; T는 String으로 추론됨
($ first-num (first-element [1 2 3])) ;; E는 Integer로 추론됨
9. 모듈 시스템
9.1. 모듈 정의: MODULE
MODULE
특수 구문은 모듈을 정의하고 어떤 심볼을 내보낼지 지정합니다.
구문:
(MODULE 모듈-이름
(EXPORT 식별자1 식별자2 ...)
;; ... 정의를 포함한 모듈 본문 ...
)
예시 (math.tpz
):
(MODULE math
(EXPORT PI add square)
($ PI 3.14159)
($ add (λ (a b) (+ a b)))
($ square (λ (n) (* n n)))
($ private-helper (λ () ...)) ;; 내보내지 않음, 내부 전용
)
9.2. 모듈 가져오기: IMPORT
IMPORT
특수 구문은 다른 모듈의 기능을 현재 스코프로 가져옵니다.
구문:
(IMPORT 모듈-이름 (식별자1 식별자2 ...))
: 특정 심볼만 가져오기(IMPORT 모듈-이름 :as 별칭)
: 모듈 전체를 별칭으로 가져오기 (권장)
예시:
;; math 모듈에서 특정 심볼 가져오기
(IMPORT math (add PI))
(io:print (core:to-string (+ (add 5 10) PI)))
;; math 모듈을 별칭으로 가져오기 (권장 방식)
(IMPORT math :as m)
(io:print (core:to-string (m:add (m:square 5) m:PI)))
10. 매크로 시스템: DEFMACRO
DEFMACRO
특수 구문은 퀘이시쿼트(quasiquote) 메커니즘을 사용하여 컴파일 타임에 코드를 변환할 수 있게 합니다.
구문: (DEFMACRO 매크로-이름 (매개변수1 매개변수2 ...) 템플릿-본문)
주요 요소:
`
(백틱/퀘이시쿼트): 대부분의 내용이 평가되지 않는 코드 템플릿을 정의,
(쉼표/언쿼트): 퀘이시쿼트 내에서 표현식을 평가하고 그 결과를 삽입,@
(쉼표-엣/언쿼트-스플라이싱): 리스트를 평가하고 그 내용을 템플릿 안으로 펼쳐서 삽입
예시:
;; 조건이 참일 때만 본문을 실행하는 'when' 매크로 정의
(DEFMACRO when (condition body-expressions...)
`(IF ,condition
(BEGIN ,@body-expressions)
NULL_SIG
)
)
;; 'when' 매크로 사용
($ x 10)
(when (> x 5)
(io:print "x는 5보다 큽니다")
(io:print "이것도 실행됩니다")
)
;; 'unless' 매크로 정의 (when의 반대)
(DEFMACRO unless (condition body-expressions...)
`(IF ,condition
NULL_SIG
(BEGIN ,@body-expressions)
)
)
표준 라이브러리와 명명 규칙
모듈 시스템 도입과 함께 Topaz는 다음과 같은 명명 규칙을 따릅니다:
Core 모듈
core
모듈은 필수적인 언어 연산을 포함하며 모든 파일에서 자동으로 가져옵니다:
+
,-
,*
,/
: 산술 연산=
,<
,>
,<=
,>=
: 비교 연산IF
,$
,λ
: 특수 구문core:to-string
: 타입 변환 함수
모듈 한정 함수
표준 라이브러리 함수들은 모듈 접두사를 사용합니다:
(io:print ...)
: 입출력 연산(string:concat ...)
: 문자열 조작(vector:map ...)
: 벡터 연산(result:ok ...)
,(result:err ...)
: Result 타입 생성자(concurrent:spawn ...)
: 동시성 연산
사용 예시:
(IMPORT string :as str)
(IMPORT vector :as vec)
($ numbers [1 2 3 4 5])
($ doubled (vec:map (λ (n) (* n 2)) numbers))
($ result-string (str:concat "두 배 결과: " (core:to-string doubled)))
(io:print result-string)
향후 언어 확장 기능
이 참조 문서는 Topaz v1.0 구문을 다룹니다. 향후 버전에는 다음이 포함될 예정입니다:
- 고급 패턴 매칭: 복잡한 데이터 타입을 해체하기 위한
MATCH
표현식 - 타입 클래스/인터페이스: 여러 타입에 걸쳐 공유되는 동작을 정의하기 위함
- Async/Await 기본 요소: 비동기 프로그래밍 패턴을 위함
- FFI (외부 함수 인터페이스): 다른 언어와의 상호 운용성을 위함
가이드와 메인 Topaz 문서 페이지를 확인하여 최신 정보를 얻으세요.
5. Topaz의 데이터 타입
이 섹션은 Topaz 언어에서 사용 가능한 내장 데이터 타입에 대한 포괄적인 개요를 제공합니다. Topaz는 강력한 타입 추론을 지원하는 정적 타입 언어로, 이는 안전성과 효율성을 위해 타입이 컴파일 타임에 검사되면서도, 모든 곳에 타입을 명시적으로 작성할 필요는 없다는 것을 의미합니다.
핵심 데이터 타입
이들은 모든 데이터 구조의 기초를 형성하는 Topaz의 근본적인 데이터 타입입니다.
숫자 (Integer
및 Float
)
Topaz는 정수(Integers)와 소수점을 가진 숫자(Floating-Point numbers)를 모두 처리합니다. 내부적인 표현 방식(예: int32
, float64
)은 컴파일러가 효율성을 위해 관리하지만, 일반적으로는 일반적인 숫자로 다루며 타입은 추론됩니다.
;; 숫자는 표기법에 따라 추론됩니다
($ age 30) ;; 정수(Integer)로 추론됨
($ count -100) ;; 정수(Integer)로 추론됨
($ price 19.99) ;; 부동 소수점 수(Float)로 추론됨
($ pi 3.1415926535) ;; 부동 소수점 수(Float)로 추론됨
;; 정밀도나 크기가 중요한 특정 시나리오를 위해
;; 향후 확장 기능에서 명시적인 타입 힌트나 접미사를 허용할 수 있지만,
;; 일반적인 사용에는 타입 추론이 선호됩니다.
불리언 (Boolean
)
전용 불리언 리터럴인 #true
와 #false
를 사용하여 참/거짓 값을 나타냅니다. 이는 숫자 표현 방식에 비해 타입 안전성과 명확성을 제공합니다.
;; 불리언 리터럴
($ is-active #true) ;; 불리언 true
($ has-permission #false) ;; 불리언 false
;; 조건 표현식에서 불리언 사용하기
(IF is-active
(io:print "시스템이 활성 상태입니다")
(io:print "시스템이 비활성 상태입니다")
)
;; 불리언 연산
($ both-true (AND #true #true)) ;; #true로 평가됨
($ either-true (OR #false #true)) ;; #true로 평가됨
($ negated (NOT #true)) ;; #false로 평가됨
문자열 (String
)
문자의 순서열을 나타내며, 일반적으로 UTF-8로 인코딩됩니다. 문자열은 큰따옴표로 둘러싸입니다.
($ name "Topaz Language")
($ message "Hello, Topaz! 👋")
($ empty-string "")
($ greeting (string:concat "Hello, " name))
심볼 (Symbol
)
심볼은 고유한 식별자로, 맵의 키, 열거형 값, 또는 해석되지 않는 프로그래밍 토큰으로 자주 사용됩니다. 컨텍스트와 원하는 평가 방식에 따라 일반적으로 콜론(:
)이나 작은따옴표('
)가 앞에 붙습니다(자세한 내용은 언어 참조에서).
($ mode :edit) ;; 키워드와 같은 심볼
($ status 'pending) ;; 다른 스타일의 심볼
($ first-name 'firstName) ;; 식별자로 사용된 심볼
벡터 (Vector
)
벡터는 다른 언어의 배열이나 리스트와 유사한, 순서가 있고 일반적으로 동일한 타입의 항목들로 구성된 컬렉션입니다. 대괄호 []
를 사용하여 정의됩니다.
($ empty-vector [])
($ numbers [1 2 3 4 5]) ;; 정수 벡터
($ strings ["hello" "world" "topaz"]) ;; 문자열 벡터
($ nested-vector [1 [2 3] 4])
;; vector 모듈을 사용한 벡터 연산
($ doubled (vector:map (λ (x) (* x 2)) numbers))
($ first-item (vector:first numbers)) ;; 1을 가져옴
($ rest-items (vector:rest numbers)) ;; [2 3 4 5]를 가져옴
맵 (Map
)
맵은 다른 언어의 딕셔너리, 해시 맵, 객체와 유사한 키-값 쌍의 컬렉션입니다. 해시 기호 다음에 괄호 (# ...)
를 사용하고 키와 값을 번갈아 나열하여 정의됩니다. 심볼이 키로 흔히 사용됩니다.
($ empty-map (#))
($ user-profile
(#
:name "Jamie Yoon"
:role "CTO"
:active #true
:projects ["Topaz" "Studio Haze"]
)
)
($ config (# "version" "1.0.2" "debug-mode" #false)) ;; 문자열 키와 불리언 값
;; map 모듈을 사용한 맵 연산
($ user-name (map:get user-profile :name)) ;; "Jamie Yoon"을 가져옴
($ updated-profile (map:assoc user-profile :active #false)) ;; 값이 업데이트된 새 맵을 반환함
프로세스 (Process
)
프로세스(함수나 람다와 유사)는 Topaz에서 일급 객체입니다. 변수에 할당될 수 있고, 인자로 전달될 수 있으며, 다른 프로세스에서 반환될 수 있습니다. (λ ...)
를 사용하여 정의됩니다. 전통적인 의미의 데이터 구조는 아니지만, 다루게 될 기본적인 값의 "타입"입니다.
($ add
(λ (a b)
(+ a b)
)
)
($ my-adder add) ;; 프로세스를 다른 변수에 할당
(io:print (core:to-string (my-adder 10 20))) ;; 30을 출력
NULL_SIG
(널 시그널)
NULL_SIG
는 Topaz에서 의미 있는 값의 부재, void 결과, 또는 '없음' 신호를 나타내는 특별하고 고유한 값입니다. 이는 0이나 빈 문자열과는 구별됩니다. 명시적으로 값을 반환하지 않는 프로세스는 암묵적으로 NULL_SIG
를 생성할 수 있습니다.
($ no-value NULL_SIG)
($ do-something-that-returns-nothing
(λ ()
(io:print "작업 수행 중...")
;; 명시적인 반환이 없으므로 NULL_SIG를 생성함
)
)
($ result (do-something-that-returns-nothing))
;; 여기서 'result'는 NULL_SIG를 가짐
사용자 정의 타입
Topaz v1.0은 커스텀 데이터 타입을 생성하기 위한 강력한 메커니즘을 지원하여, 타입 안전성과 명확한 데이터 모델링 능력을 제공합니다.
구조체 타입 (DEFINE-TYPE
)
DEFINE-TYPE
을 사용하여 이름 있는 필드와 해당 타입을 갖는 구조화된 데이터 타입(struct나 record와 유사)을 생성합니다.
구문: (DEFINE-TYPE 타입이름 (# :필드이름1 필드타입1 :필드이름2 필드타입2 ...))
;; 부동 소수점 좌표를 갖는 Point 타입 정의
(DEFINE-TYPE Point (# :x Float :y Float))
;; 여러 필드 타입을 갖는 Person 타입 정의
(DEFINE-TYPE Person (# :name String :age Integer :active Boolean))
;; 다른 사용자 정의 타입을 사용하여 중첩 타입 정의
(DEFINE-TYPE Rectangle (# :top-left Point :bottom-right Point))
;; 타입 구조와 일치하는 맵 리터럴을 사용하여 인스턴스 생성
($ origin (# :x 0.0 :y 0.0)) ;; 타입: Point
($ user (# :name "Alice" :age 30 :active #true)) ;; 타입: Person
($ rect (# :top-left origin :bottom-right (# :x 10.0 :y 10.0))) ;; 타입: Rectangle
열거형 타입 (DEFINE-ENUM
)
DEFINE-ENUM
을 사용하여 고정된 값 집합을 갖는 타입을 생성하며, 이는 상태 머신, 설정 옵션, 도메인 모델링에 유용합니다.
구문: (DEFINE-ENUM 열거형이름 :값1 :값2 :값3 ...)
;; 기본 열거형 정의
(DEFINE-ENUM Color :RED :GREEN :BLUE :YELLOW)
(DEFINE-ENUM Status :PENDING :IN_PROGRESS :COMPLETED :FAILED :CANCELLED)
(DEFINE-ENUM Direction :NORTH :SOUTH :EAST :WEST)
;; 열거형 값 사용
($ current-color :RED)
($ task-status :IN_PROGRESS)
($ facing :NORTH)
;; 열거형은 조건 논리와 잘 작동함
(IF (= current-color :RED)
(io:print "정지!")
(io:print "진행")
)
제네릭 타입
Topaz는 제네릭 타입 매개변수를 통해 파라메트릭 다형성을 지원하여, 여러 타입과 함께 작동하는 재사용 가능한 코드를 작성할 수 있게 합니다.
;; 모든 타입 T와 함께 작동하는 제네릭 함수
($ identity
(λ [T] (value: T)
value
)
)
;; 모든 요소 타입 E의 벡터를 위한 제네릭 함수
($ vector-length
(λ [E] (vec: (Vector E))
(vector:length vec)
)
)
;; 타입 매개변수를 사용하여 제네릭 데이터 구조를 정의할 수 있음
;; 참고: 제네릭 타입 정의를 위한 정확한 구문은 향후 언어 확장의 일부입니다
;; (DEFINE-TYPE Maybe [T] (# :some T | :none NULL_SIG)) ;; 미래 구문 예시
사용자 정의 타입 작업
;; 패턴 매칭 및 필드 접근 (맵 연산 사용)
($ get-person-info
(λ (person: Person)
($ name (map:get person :name))
($ age (map:get person :age))
(string:concat name " is " (core:to-string age) " years old")
)
)
;; 타입-안전 연산
($ calculate-distance
(λ (p1: Point p2: Point)
($ dx (- (map:get p2 :x) (map:get p1 :x)))
($ dy (- (map:get p2 :y) (map:get p1 :y)))
(math:sqrt (+ (* dx dx) (* dy dy)))
)
)
;; 함수 사용하기
($ alice (# :name "Alice" :age 30 :active #true))
($ point1 (# :x 0.0 :y 0.0))
($ point2 (# :x 3.0 :y 4.0))
(io:print (get-person-info alice)) ;; "Alice is 30 years old"
(io:print (core:to-string (calculate-distance point1 point2))) ;; "5.0"
추가 정보
이러한 타입들이 언어의 문법과 연산 내에서 어떻게 사용되는지에 대한 더 자세한 내용은 구문 참조를 참조하십시오. 타입 추론 세부 사항, 제네릭(파라메트릭 다형성), 그리고 커스텀 타입 정의의 구체적인 내용과 같은 고급 주제는 언어가 발전함에 따라 전용 가이드에서 다룰 예정입니다.
6. Topaz에서의 함수와 프로세스
Topaz에서 함수는 더 정확하게는 **프로세스(Process)**라고 불립니다. 프로세스는 논리와 추상화를 위한 핵심적인 구성 요소입니다. 이 언어의 핵심 원칙은 프로세스가 **일급 시민(first-class citizens)**이라는 것입니다. 이 원칙은 함수형 프로그래밍 개념을 언어에 깊숙이 내장하여 프로세스에 강력한 힘과 유연성을 부여합니다.
프로세스 정의하기
프로세스는 일반적으로 λ
(람다) 특별 폼을 사용하여 익명 함수로 생성됩니다. 프로세스에 이름을 부여하려면 $
특별 폼을 사용하여 이 익명 프로세스를 식별자에 바인딩합니다.
문법:
($ 프로세스_이름
(λ (매개변수_1 매개변수_2 ...)
;; 여기에 본문 표현식이 들어갑니다.
;; 마지막 표현식의 결과가 반환됩니다.
)
)
예시:
;; 두 숫자를 더하는 간단한 프로세스
($ add
(λ (x y)
(+ x y)
)
)
;; 프로세스 호출은 다른 연산과 동일합니다
(add 5 10) ;; 15로 평가됩니다
일급 시민 (First-Class Citizens)
"일급"이라는 것은 프로세스가 다른 데이터 값(예: 숫자나 문자열)처럼 취급된다는 의미입니다. 프로세스는 다음과 같은 작업이 가능합니다:
1. 변수/식별자에 저장
프로세스를 식별자에 바인딩할 수 있습니다. 이를 통해 이름으로 프로세스를 참조하고, 다른 식별자에 할당할 수도 있습니다.
($ greeting-process (λ (name) (CONCAT "Hello, " name)))
($ say-hello greeting-process) ;; 프로세스 값을 새로운 식별자에 할당
(say-hello "Topaz") ;; "Hello, Topaz"로 평가됩니다
2. 인자로 전달
프로세스를 다른 프로세스에 인자로 전달할 수 있습니다. 이는 콜백(callback)이나 고차 함수(higher-order function)와 같은 강력한 패턴을 가능하게 하는 기본 개념입니다.
;; 다른 프로세스 'f'와 값 'v'를 인자로 받아,
;; 'v'에 'f'를 적용하는 프로세스
($ apply-it
(λ (f v)
(f v)
)
)
($ square (λ (n) (* n n)))
;; 여기서 'square' 프로세스를 인자로 전달합니다.
(apply-it square 10) ;; 100으로 평가됩니다
;; 제네릭 고차 함수 예시
($ compose
(λ [A B C] (f: (Process B C) g: (Process A B))
(λ (x: A)
(f (g x))
)
)
)
3. 다른 프로세스에서 반환
프로세스는 다른, 종종 특화된, 프로세스를 생성하여 반환할 수 있습니다.
;; 이 프로세스는 단지 값을 반환하는 것이 아니라 새로운 프로세스를 반환합니다.
($ make-adder
(λ (amount-to-add)
;; 이 내부 람다가 반환되는 부분입니다.
(λ (n)
(+ n amount-to-add)
)
)
)
;; adder의 특화된 버전을 만듭니다.
($ add-five (make-adder 5))
($ add-ten (make-adder 10))
(add-five 100) ;; 105로 평가됩니다
(add-ten 100) ;; 110으로 평가됩니다
이 강력한 패턴은 **클로저(Closure)**를 활용합니다. 클로저를 통해 반환된 내부 프로세스는 자신이 생성된 환경의 amount-to-add
값을 "기억"합니다.
재귀 (Recursion)
많은 함수형 언어와 마찬가지로 Topaz에서는 반복을 전통적인 for
나 while
루프 대신 **재귀(recursion)**를 통해 가장 자연스럽게 구현합니다. 이 접근 방식은 부수 효과(side effect)와 상태 변경을 피함으로써 불변성(immutability) 원칙에 부합합니다.
;; 숫자의 팩토리얼을 계산하는 재귀 프로세스
($ factorial
(λ (n)
(IF (<= n 1)
1 ;; 기본 케이스: 0 또는 1의 팩토리얼은 1입니다.
(* n (factorial (- n 1))) ;; 재귀 단계: n * factorial(n-1).
)
)
)
(factorial 5) ;; 120으로 평가됩니다 (5 * 4 * 3 * 2 * 1)
;; 더 나은 성능을 위한 꼬리 재귀 버전
($ factorial-tail
(λ (n)
($ factorial-helper
(λ (n acc)
(IF (<= n 1)
acc
(factorial-helper (- n 1) (* n acc))
)
)
)
(factorial-helper n 1)
)
)
제네릭 및 고차 프로세스
Topaz v1.0은 제네릭 타입 매개변수와 고차 함수를 모두 지원하여 강력한 추상화를 가능하게 합니다.
제네릭 프로세스
제네릭 프로세스는 타입 매개변수를 선언하여 여러 타입과 함께 작동할 수 있습니다:
;; 제네릭 항등 함수
($ identity
(λ [T] (value: T)
value
)
)
;; 벡터를 위한 제네릭 map 함수
($ vector-map
(λ [A B] (f: (Process A B) vec: (Vector A))
;; 구현은 표준 라이브러리에서 제공될 것입니다
(vector:map f vec)
)
)
;; 타입 추론과 함께 사용
($ numbers [1 2 3 4])
($ doubled (vector-map (λ (x) (* x 2)) numbers)) ;; A=Integer, B=Integer로 추론됨
커링(Currying)과 부분 적용(Partial Application)
Topaz는 람다 문법을 통해 자연스럽게 커링을 지원합니다:
;; 커링된 덧셈 함수
($ add-curried
(λ (x)
(λ (y)
(+ x y)
)
)
)
;; 부분 적용을 통해 특화된 함수 생성
($ add-five (add-curried 5))
($ add-ten (add-curried 10))
(io:print (core:to-string (add-five 7))) ;; "12"를 출력
(io:print (core:to-string (add-ten 20))) ;; "30"을 출력
7. Topaz에서의 제어 흐름
Topaz는 주로 동작을 수행하는 명령형 구문보다는 값으로 평가되는 표현식을 통해 실행 흐름을 관리합니다. 이러한 함수형 접근 방식은 더 예측 가능하고 조합 가능한 코드를 만들어냅니다. 이 섹션에서는 Topaz v1.0에서 프로그램 흐름을 제어하는 주요 메커니즘을 다룹니다.
조건부 평가: IF
조건 분기를 위한 기본 도구는 IF
특별 폼입니다. 이 폼은 조건을 평가하고 그 결과에 따라 두 가지 가능한 표현식 중 하나를 평가합니다.
문법: (IF 조건_표현식 참_표현식 거짓_표현식)
조건_표현식
을 평가합니다.#true
는 참으로,#false
또는NULL_SIG
는 거짓으로 취급됩니다.- 조건이 참이면
참_표현식
을 평가하고 그 결과를 반환합니다. - 조건이 거짓이면
거짓_표현식
을 평가하고 그 결과를 반환합니다.
($ temperature 25)
($ clothing-advice
(IF (> temperature 20)
"따뜻하니, 티셔츠를 입으세요!"
"쌀쌀하니, 재킷을 고려해보세요."
)
)
;; clothing-advice의 값은 "따뜻하니, 티셔츠를 입으세요!" 입니다.
;; 중첩된 조건문
($ grade 85)
($ letter-grade
(IF (>= grade 90)
"A"
(IF (>= grade 80)
"B"
(IF (>= grade 70)
"C"
"F"
)
)
)
)
재귀와 고차 함수를 통한 반복
Topaz는 함수형 언어의 뿌리에 충실하게 for
나 while
같은 전통적인 명령형 루프보다 선언적인 반복 접근 방식을 선호합니다. 이는 주로 재귀와 고차 함수를 통해 달성됩니다.
재귀
함수와 프로세스 가이드에서 보여준 바와 같이, 재귀는 특히 벡터와 같은 데이터 구조에서 반복을 수행하는 자연스럽고 강력한 방법입니다. 이 패턴은 종종 컬렉션의 첫 번째 요소를 처리한 다음, 컬렉션의 나머지 부분에 대해 재귀적으로 프로세스를 호출하는 것을 포함합니다.
예시: 벡터 내 숫자들의 합 구하기
($ sum-vector
(λ (vec)
(IF (vector:is-empty vec)
0 ;; 기본 케이스: 빈 벡터의 합은 0
(+ (vector:first vec) (sum-vector (vector:rest vec))) ;; 재귀 단계
)
)
)
(sum-vector [10 20 30 40]) ;; 100으로 평가됩니다
참고: IS-EMPTY
, FIRST
, REST
는 표준 라이브러리에 포함될 일반적인 리스트/벡터 조작 함수에 대한 예시 이름입니다.
고차 함수
컬렉션을 처리하는 더 선언적이고 종종 선호되는 방법은 다른 프로세스를 인자로 받는 프로세스인 고차 함수를 사용하는 것입니다. map
, filter
, reduce
와 같은 표준 함수들은 이 패러다임에서 필수적인 도구입니다.
($ numbers [1 2 3 4 5])
;; MAP: 모든 요소에 프로세스를 적용하여 결과로 새로운 벡터를 반환합니다.
($ squared (vector:map (λ (n) (* n n)) numbers))
;; squared의 값은 [1 4 9 16 25] 입니다.
;; FILTER: 특정 조건을 만족하는 요소만 포함하는 새로운 벡터를 반환합니다.
($ evens (vector:filter (λ (n) (= (% n 2) 0)) numbers))
;; evens의 값은 [2 4] 입니다.
;; REDUCE: 프로세스를 반복적으로 적용하여 모든 요소를 단일 값으로 결합합니다.
($ sum (vector:reduce + 0 numbers)) ;; 초기값 0으로 시작합니다.
;; sum의 값은 15 입니다.
;; 평가 순서를 더 세밀하게 제어하기 위한 FOLD-LEFT와 FOLD-RIGHT
($ concatenated (vector:fold-left string:concat "" ["Hello" " " "Topaz" "!"]))
;; concatenated의 값은 "Hello Topaz!" 입니다.
제어 흐름을 위한 매크로
Topaz v1.0에는 사용자 정의 제어 흐름 구조를 만들 수 있는 매크로 시스템이 포함되어 있습니다.
;; 조건이 참일 때만 본문을 실행하는 'when' 매크로 정의
(DEFMACRO when (condition body-expressions...)
`(IF ,condition
(BEGIN ,@body-expressions)
NULL_SIG
)
)
;; 'when' 매크로 사용
($ x 10)
(when (> x 5)
(io:print "x는 5보다 큽니다")
(io:print "이것도 실행됩니다")
)
;; 'unless' 매크로 정의 (when의 반대)
(DEFMACRO unless (condition body-expressions...)
`(IF ,condition
NULL_SIG
(BEGIN ,@body-expressions)
)
)
;; 여러 조건을 위한 'cond' 매크로 정의 (Lisp의 cond와 유사)
(DEFMACRO cond (clauses...)
;; 구현은 중첩된 IF 표현식으로 확장될 것입니다
;; 이것은 단순화된 개념적 예시입니다
`(IF ,(first (first clauses))
,(second (first clauses))
(cond ,@(rest clauses))
)
)
;; cond 매크로 사용
($ grade 85)
($ letter (cond
((>= grade 90) "A")
((>= grade 80) "B")
((>= grade 70) "C")
(#true "F") ;; 기본 케이스
))
패턴 매칭 (향후 확장)
Topaz의 향후 버전에는 복잡한 데이터 구조를 분해하고 분기하는 데 훨씬 더 강력하고 표현적인 제어 흐름을 제공할 패턴 매칭을 위한 MATCH
표현식이 포함될 예정입니다:
;; Result 타입을 처리하기 위한 미래의 MATCH 표현식
(MATCH some-result
((result:ok value) (io:print (string:concat "성공! 값: " value)))
((result:err message) (io:print (string:concat "실패! 이유: " message)))
)
;; 사용자 정의 타입에 대한 패턴 매칭
(MATCH user-input
((# :type :login :username u :password p) (authenticate u p))
((# :type :logout :session-id sid) (logout sid))
((# :type :unknown) (io:print "알 수 없는 명령어"))
)
8. Topaz에서의 오류 처리
Topaz v1.0은 견고하고 예측 가능한 소프트웨어를 만드는 데 중점을 두고 설계되었습니다. 이를 위해 대부분의 복구 가능한 오류에 대해 전통적인, 확인되지 않은 예외 처리보다는 명시적인 오류 처리 방식인 대수적 데이터 타입(ADT), 주로 Result
와 Option
타입을 선호합니다.
이 접근 방식은 잠재적인 실패를 프로세스 시그니처의 가시적이고 필수적인 부분으로 만들어, 개발자가 이를 인지하고 신중하게 처리하도록 강제하여 더 회복력 있는 애플리케이션을 만들게 합니다.
Result
타입
Result
는 연산의 두 가지 가능한 결과, 즉 성공 또는 실패 중 하나를 나타냅니다. 이것은 실패할 수 있는 연산을 처리하는 주요 도구입니다.
(result:ok 값)
: 성공적인 결과 값을 포함합니다. 예:(result:ok 42)
.(result:err 오류_정보)
: 무엇이 잘못되었는지 설명하는 오류 값(예: 문자열 또는 더 구조화된 오류 타입)을 포함합니다. 예:(result:err "파일을 찾을 수 없습니다")
.
실패할 수 있는 함수는 Result
타입을 반환하도록 설계되어, 이를 사용하는 모든 사람에게 그 동작이 명확해집니다.
예시: 안전한 나눗셈 프로세스
;; Result 타입을 반환하는 "안전한 나눗셈" 프로세스
($ safe-divide
(λ (numerator denominator)
(IF (= denominator 0)
(result:err "0으로 나누기는 허용되지 않습니다.") ;; 실패 시 오류 반환
(result:ok (/ numerator denominator)) ;; 성공 시 값과 함께 성공 반환
)
)
)
($ result1 (safe-divide 10 2)) ;; (result:ok 5)로 평가됨
($ result2 (safe-divide 10 0)) ;; (result:err "0으로 나누기는 허용되지 않습니다.")로 평가됨
Result
값 다루기
내부 값에 접근하려면 Result
를 "풀거나(unwrap)" 처리해야 합니다. 이는 일반적으로 조건부 논리나, 향후 버전에서는 더 발전된 패턴 매칭을 통해 수행됩니다.
예시: Result 처리하기
($ handle-division-result
(λ (result)
(IF (result:is-ok result) ;; 결과가 성공인지 확인
(io:print (string:concat "성공! 값은: " (string:to-string (result:get-value result))))
(io:print (string:concat "오류가 발생했습니다: " (result:get-error result)))
)
)
)
(handle-division-result result1) ;; "성공! 값은: 5"를 출력
(handle-division-result result2) ;; "오류가 발생했습니다: 0으로 나누기는 허용되지 않습니다."를 출력
참고: result:ok
, result:err
, result:is-ok
, result:get-value
, result:get-error
는 표준 라이브러리의 일부인 Result
타입의 생성자 및 헬퍼 함수입니다.
실패 가능한 연산 체이닝하기
Result
타입의 진정한 힘은 어떤 단계에서든 실패할 수 있는 일련의 연산을 수행해야 할 때 빛을 발합니다. 이 모델을 사용하면 오류가 발생하는 즉시 전체 시퀀스를 단락(short-circuit)시키면서 이러한 연산들을 우아하게 체이닝할 수 있습니다.
개념적 예시:
;; 가상의 'result:then' 프로세스는 Result와 다른 프로세스를 인자로 받습니다.
;; Result가 OK일 경우에만 프로세스를 적용합니다.
;; Result가 ERR이면, 오류를 그대로 전달합니다.
($ first-step (safe-divide 100 2)) ;; -> (result:ok 50)
($ second-step (result:then first-step (λ (value) (safe-divide value 5)))) ;; -> (result:ok 10)
($ final-result (result:then second-step (λ (value) (safe-divide value 10)))) ;; -> (result:ok 1)
;; 이제 오류를 발생시켜 봅시다.
($ failing-step (result:then first-step (λ (value) (safe-divide value 0)))) ;; -> (result:err "0으로 나누기...")
($ final-result-with-error (result:then failing-step (λ (value) (safe-divide value 2))))
;; 마지막 단계는 절대 실행되지 않습니다. 최종 결과는 여전히 첫 번째 오류입니다.
;; final-result-with-error는 (result:err "0으로 나누기...") 입니다.
이는 Result
가 어떻게 오류 처리가 나중에 추가되는 것이 아니라 내장된, 깨끗하고 회복력 있는 데이터 처리 파이프라인을 만들 수 있는지를 보여줍니다.
Option
타입 (값의 부재 처리)
때로는 값의 부재가 "오류"가 아니라 예상되고 유효한 결과일 수 있습니다. 이러한 경우를 위해 Option
타입이 사용됩니다. 이는 값의 존재 또는 부재를 나타냅니다.
(option:some 값)
: 값을 포함합니다. 예:(option:some 42)
.(option:none)
: 값의 부재를 나타냅니다. 이는 개념적으로NULL_SIG
와 유사하지만 명확성을 위해Option
타입 시스템 내에서 명시적으로 사용됩니다.
예시: 안전한 맵 조회
($ my-config (# :host "topaz.ooo" :port 80))
;; Option 타입을 반환할 수 있는 안전한 맵 조회
($ get-port (map:get my-config :port)) ;; 개념적인 (option:some 80)으로 평가됨
($ get-user (map:get my-config :user)) ;; 개념적인 (option:none)으로 평가됨
(IF (option:is-some get-user)
(io:print "설정에서 사용자를 찾았습니다.")
(io:print "설정에서 사용자를 찾을 수 없습니다.")
)
참고: option:some
, option:none
, option:is-some
, map:get
은 Option
타입의 생성자 및 관련 헬퍼 함수입니다.
문서 정보
- 총 섹션 수: 8
- 생성일: 2025-06-06 11:27:25
- 버전: Topaz v1.0
- 목적: 외부 전문가 검토 및 종합 레퍼런스
이 통합 문서는 v1.0 기준의 완전한 Topaz 프로그래밍 언어 사양 및 문서를 나타냅니다. 모든 구문 정의, 타입 시스템 사양, 모듈 시스템, 매크로 시스템 및 실용적인 예제가 포함되어 있습니다.
최신 업데이트 및 개별 파일은 content/docs/ 디렉토리의 원본 문서를 참조하십시오.