Scheme 기본 문법
Scheme 언어의 특징은 아래와 같다
- Simple syntax - 간단한 문법
- Functional programming - 함수가 일급 객체 취급 받는다
- Dynamic typing - 동적 타입 지원
- Tail recursion optimization - 꼬리 재귀 최적화
Basic Data Type
s-expression은 symbolic expression의 약어로, Lisp 언어에서 모든 코드나 데이터를 나타내는 방식을 말합니다.
이는 리스트 구조를 이용한 트리 구조로 표현됩니다.
따라서 Lisp에서는 코드도 데이터와 마찬가지로 리스트 형태로 표현되어 처리됩니다.
S-expression의 데이터 유형
- Atom은 숫자, 심볼 등과 같은 단순한 데이터 유형을 나타냅니다.
- List는 여러 Atom이나 다른 List를 요소로 포함하는 복합 데이터 유형입니다.
- List는 괄호로 둘러싸여 있으며, 각 요소는 공백으로 구분됩니다.
- Others는 구조체, 문자열, 벡터 등 다른 데이터 유형을 포함합니다.
예시
- 포인터로 연결 되어 있다고 생각하면 이해하기 수월합니다
Operations
Scheme 언어에서 다루는 operation들의 이름, 기능, 예시는 아래와 같습니다.
Car : Return First Element : 첫 번째 요소 반환
- (car '((a) b c))
- 결과 : ’ (a)
- (car ’ (( )))
- 결과 : ’ ( )
- (car ’ ( ))
- 결과 : error, Null, false or empty List
Cdr : Return Except First element(list type) : 첫 번째 요소 제외하고, 나머지 반환
- (cdr '(a (b c)))
- 결과 : '((b c))
- (cdr '((a b ) c ))
- 결과 : '©
- (cdr ’ (()))
- 결과 : ’ ()
- (cdr ’ ())
- 결과 : error, Null, False or Empty List
Cadr, Cdar
- cadr = car + cdr (오른쪽에서 왼쪽으로 계산)
- = (cadr ’ (a b c))
- = (car (cdr ’ (a b c )'))
- = (car ’ (b c))
- b
Cons : 주어진 원소를 리스트의 앞부분에 추가하는 함수
- cons와 append의 차이는 뭘까
- cons는 원소를 리스트의 앞에 추가하는 반면, append는 2개를 연결하여 새로운 리스트를 만듭니다
- 예시: (cons 'a '(b c)) => (a b c)
- 리스트도 하나의 요소이기 때문에, 리스트와 리스트를 cons 하면 list의 list가 나옵니다
Append : 두 개 이상의 리스트를 이어 붙임
- 예시: (append '(a) '(b c)) => (a b c)
Define : 변수나 함수 정의
define
을 사용하여 변수를 정의할 때는 변수 이름과 초기값을 지정합니다.
함수를 정의할 때는 함수 이름, 매개 변수 및 함수 몸체를 지정합니다.
define
을 사용하여 정의된 변수나 함수는 다른 식에서 참조할 수 있습니다.
이를테면, (define x 5)
는 x
라는 변수를 정의하고 초기값으로 5를 할당합니다.
이후에는 x
를 참조하여 5를 사용할 수 있습니다.
함수를 정의할 때는 다음과 같이 사용할 수 있습니다.
(define (add x y) (+ x y))
는 add
라는 함수를 정의하고, 매개 변수로 x
와 y
를 받으며, x
와 y
를 더한 값을 반환합니다.
이후에는 (add 3 4)
와 같이 add
함수를 호출하여 3과 4를 더한 값을 반환받을 수 있습니다.
Set! : 변수 값을 변경하기 위해 사용되는 형식
수를 새로운 값으로 할당하는 것으로 변수가 가리키는 값이 변경됩니다. 이것은 기존의 변수를 수정할 때 사용됩니다. 예를 들어, 다음과 같이 사용할 수 있습니다.
- 사전에 값을 정의하지 않으면 에러가 발생한다
(define x 10) ; x에 10 할당
(set! x 20) ; x의 값을 20으로 변경
(display x) ; 20이 출력됩니다.
set!
은 일반적으로 전역 변수의 값을 변경하기 위해 사용되지만, 로컬 변수에도 적용될 수 있습니다.
그러나 로컬 변수의 경우 let
또는 let*
를 사용하여 변수를 할당하고 값을 변경하는 것이 좋습니다.
Numeric Operaions
-
(+)
=> 0(+ 1 2 3)
=> 6(+ 1.5 2.5)
=> 4.0
-
(- 3 2)
=> 1(- 5)
=> -5(- 1.5 0.5)
=> 1.0
-
(*)
=> 1(* 2 3)
=> 6(* 2.0 3.0)
=> 6.0
-
(/ 10 5)
=> 2(/ 1.0 2)
=> 0.5(/ 10 0)
=> 에러 발생
-
(> 2 1)
=>#t
(> 1 2)
=>#f
(> 1 1)
=>#f
-
(< 2 1)
=>#f
(< 1 2)
=>#t
(< 1 1)
=>#f
-
(>= 2 1)
=>#t
(>= 1 2)
=>#f
(>= 1 1)
=>#t
-
(<= 2 1)
=>#f
(<= 1 2)
=>#t
(<= 1 1)
=>#t
-
(= 1 1)
=>#t
(= 1 2)
=>#f
(= 1 1 1)
=>#t
- 문자들에게는 적용이 되지 않음 - Equal?을 써야 한다
-
(min 1 2)
=> 1(min 2 1)
=> 1(min 1 1)
=> 1
-
(max 1 2)
=> 2(max 2 1)
=> 2(max 1 1)
=> 1
Logical Operations
-
- (and
#t
#t
#t
) =>#t
- (and
#t
#f
#t
) =>#f
- (and '() 1 2 3 4 5) => 5
- (and
-
- (or
#t
#f
#t
) =>#t
- (or
#f
#f
#f
) =>#f
- (or ’ () 1 2 3 4 5) => '()
- (or
-
- (not
#t
) =>#f
- (not
#f
) =>#t
- (not
==Other Operations
-
cons, append, list의 차이는 무엇인가
-
List : 주어진 요소를 하나의 리스트로 만듭니다
- (list 'a 'b 'c) => (a b c)
- (list (list 'a 'b) (list 'c)) => ((a b) ©)
- (list '()) => (())
-
==Member : 리스트에서 요소를 찾습니다
- (첫 번째 매치 되는 요소부터 쭈욱 반환합니다)
- (member 'a '(1 a b)) => (a b)
- (member (list 'a) '(a (a) c (a))) => ((a) c (a))
- (member 'd '(a b c)) =>
#f
-
==Assoc : 주어진 키가 리스트 내에 존재하는지 확인, 존재하면 키와 연관된 값 반환
- (assoc 'b '((a 1) (b 2) (c 3))) => (b 2)
- (assoc '(a) '(((a) 1 2 3) (b 4) (c 5))) => ((a) 1 2 3)
- (assoc 'd '((a 1) (b 2) (c 3))) =>
#f
-
Length : 무조건 리스트로 주어져야 길이를 계산 함
- (length '(a b c)) => 3
- (length '()) => 0
- (length '((a b) ())) => 2
-
Reverse
- (reverse '(a b c)) => (c b a)
- (reverse '((a b) c)) => (c (a b))
-
Equal
- (equal? 'a 'a) =>
#t
- (equal? 1 1) =>
#t
- (equal? '(a (b)) '(a (b))) =>
#t
- (equal? '(a (b)) '(a ©)) =>
#f
- (equal? 'a 'a) =>
-
==apply : 리스트 형태로 넘겨진 인자를 함수의 인자로 전달하는 함수
- (apply + '(1 2 3)) => 6
- (apply min '(5 2 8 1)) => 1
- (apply append '((1 2) (3 4))) => (1 2 3 4)
Loop Operations- 여기
- ==Map
- 리스트에 대해 함수를 반복 적용하여 새로운 리스트 생성
- (map car '((a 1) (b 1) (c 2))) => '(a b c)
- ==for-each
- (for-each (lambda (n) (set! x (+ x n))) '(1 2 3 4))
- => side effect, return 값 없음
- (for-each (lambda (n) (set! x (+ x n))) '(1 2 3 4))
- Let: 지역 변수를 정의하고, 로컬 변수를 사용하여 식을 계산하고 결과를 반환
- (let ((x 1) (y 2)) (+ x y)) => 3
- ==(let ((x 1) (y 2)) (set! x (+ x y)))
- => side effect, return 값 없음
- 전역 변수 값 설정 할 때 사용
==Control Statement
- Scheme에서는
if
,case
,cond
등의 Control Statement를 지원합니다.
if
- 조건식이 참이면
then
부분의 표현식을 실행하고, 그렇지 않으면else
부분의 표현식을 실행합니다.else
부분은 선택적입니다. (if cond expr1 expr2) (if cond1 expr1 (if cond2 expr2 expr3))
- 조건식이 참이면
case
key
값과index
를 비교하여 일치하는 경우 해당expr
을 반환합니다.else
부분은 선택적입니다.(case key (index1 expr1) (index2 expr2) (else exprn))
cond
: 다중 if 문을 염두해둔 것이다cond
부분의 조건이 참일 때, 해당expr
을 반환합니다.else
부분은 선택적입니다.(cond (cond1 expr1) (cond2 expr2) ... (cond_n expr_n) (else expr))
(if (= 3 (+ 1 2)) (+ 3 4) 2) => 7
(case (* x y) (3 'three) (4 'four) (else 'none)) => 'four
(cond ((> 3 2) 'greater) ((< 3 2) 'less) (else 'none-above)) => 'greater
ETC : Fuction, Let, Block Structing, Let Loop, Recursion
-
함수(function)
Scheme에서 함수를 정의할 때는 define을 사용하며, define을 사용하여 함수를 정의할 수 있습니다.
함수는 입력 매개변수와 함께 작동하는 명령어의 집합으로 정의됩니다.
예를 들어, (define (add2 x) (+ x 2))는 add2라는 함수를 정의합니다.
이 함수는 x라는 매개변수를 입력으로 받고, x에 2를 더한 값을 반환합니다.
이 함수를 (add2 4)와 같이 호출하면, 4를 매개변수로 사용하여 6을 반환합니다. -
let
지역 변수(local variable)를 정의하는 데 사용됩니다. -
예를 들어, (let ((x 1) (y 2) (z 5)) (+ x y z))는 x, y, z라는 세 개의 지역 변수를 정의하고, x와 y를 더한 다음 z를 더하여 8를 반환합니다.
let으로 지역 함수도 만들 수 있다!
> (define (cm item lst)
(let loop((temp lst))
(cond
((null? temp) '())
((equal? item (car temp)) temp)
(else (loop (cdr temp)))
)
)
)
> (cm 'b '(a b c))
(b c)
-
block structuring
(define (fn arg) …)은 함수를 정의하며, (let ((a 1) (b 2)) …)은 지역 변수를 정의합니다.
(begin …)은 여러 개의 Scheme 표현식을 그룹화하고 순차적으로 실행하며, (if …)는 조건문을 나타냅니다. -
재귀(recursion)
재귀는 함수가 자기 자신을 호출하여 실행되는 것을 말합니다.
예를 들어,(define (factorial n) (if (= n 0) 1 (* n (factorial (- n 1)))))
는 팩토리얼을 계산하는 함수를 정의합니다.
이 함수는 재귀를 사용하여 자기 자신을 호출하면서 입력된 n까지의 모든 정수를 곱하여 반환합니다.
또한, 재귀를 보다 효율적으로 수행하기 위해 꼬리 재귀(tail recursion)를 사용할 수 있습니다.
꼬리 재귀는 함수 호출이 반환 값 계산의 마지막 단계에 있을 때 재귀 호출을 제거하므로, 스택 오버플로우와 같은 문제를 방지할 수 있습니다.
레퍼런스
- 꼬리 재귀(tail recursion) 최적화
- [[일급 객체(first class)]]
부족한 점이나 잘못 된 점을 알려주시면 시정하겠습니다 :>
'Computer Science > 프로그래밍 언어론' 카테고리의 다른 글
어휘 분석 (0) | 2023.04.05 |
---|---|
프로그래밍 언어의 구성 (0) | 2023.04.05 |
람다 대수(Lamda calcuus)란 무엇인가 (0) | 2023.03.29 |
함수형 프로그래밍 (0) | 2023.03.29 |
프로그래밍 언어의 변천사 (0) | 2023.03.27 |