racket 언어 문법 조금만 살펴보기
lisp 언어를 이 책 통해서 처음 접해서 전문성이 없는 글입니다. 참고바랍니다.
소개
lisp/scheme
계열인racket
언어로 프로그래밍 구조 예시를 보여준다 .
실행방법
A. Racket + VSC 사용
B. Replit
Replit에서 Racket 언어를 제공해준다.
이 책을 어떻게 봐야할까?
인터넷에 이 책에 대한 평가가 좋은데 그에 비해 내용이 잘 읽히지 않아 당혹스러웠던 적이 있다. lisp
은 괄호가 워낙 많아 타언어에 비해 가독성이 안 좋고 요즘 언어들과 조금 다른 스타일의 문법을 가지고 있기 때문이다. 그렇기 때문에 나같이 코딩 경력이 짧은 사람들은 다른 언어로 번역해가면서 그 의미를 이해해보는 것도 나쁘지 않다.
여기서는 주로 python과 JS/TS와 비교해서 이 책이 말하고자하는 바를 파악하려고 한다.
기본 문법
- 이 책의 뒷부분의 Appendix B. 항목을 참고한다.
- Racket 공식홈페이지의 가이드를 참고한다
조합
프로시저 적용(procedure application)이라고도 부를 수 있는 조합 combination은 괄호로 감싼다.
1
(연산자 피연산자1 ... 피연산자n)
- 흔히들 stack식 계산 방식인전위 표기법 으로 연산처리한다.
- 어셈블리 언어에서도 가끔 보이는 표현방식이다.
add $s1, $s2, $s3
수식은$s1 = $s2 + $s3
표현과 같다.
람다표현식
수를 지칭하기 위해 수치 리터럴1 을 사용하는 것처럼, 프로시저를 지칭할 때는 lambda로 시작하는 람다표현식을 자주 사용한다.
1
(lambda (x) (* x x))
위 표현식은 js, python으로 나타내면 다음과 같다.
1
2
my_func = lambda x : x * x
my_func(4) # 16
참고로 파이썬의 경우 lambda
함수는 한 줄만 작성할 수 있어 위 racket의 lambda나 js의 arrow function이랑 다르다.
1
2
const func = x => x*x;
func(4) // 16
정의
define
키워드로 특정 값, 프로시저에 이름을 부여하는 방식이다.
1
2
(define pi 3.141592653589793)
(define square (lambda (x) (* x x)))
이건 C언어의 매크로랑 유사하다.
1
2
#define pi 3.14159265
#define square(x) ((x)*(x)) // 괄호 처리 잘 안 하면 연산 순서가 의도대로 동작 안 할 수 있다.
또 racket
처럼 프로시저 겹치는 방식도 가능은 하나, 다른 언어들에 불편하니 참고만 하자.
조건문
racket
에서는 조건문을 나타내는 방식이 총 2가지다.cond
를 사용하면switch~case
문 같은 느낌으로 사용할 수 있다.else if
구문이 없으니 세 가지 이상의 조건문을 달 때는cond
를 사용하자.
1
2
3
4
5
6
(define (abs x)
(cond ((< x 0) (- x)) ; x<0 이면 -x 반환
((= x 0) x) ; x = 0 이면 x 반환
((> x 0) x) ; x>0이면 x 반환
)
)
cond
의 마지막 절에는 술어로 사용할 수 있는else
키워드를 사용할 수 있다.1 2 3 4 5 6
(define (abs x) (cond ((< x 0) (- x)) ((= x 0) x) (else x) ; else 구문 사용! ) )
if
문은 이분법적인 상황에 쓰인다.- 위 예제랑 똑같이 음수일 때만 절댓값 반환하는 함수를 만들어보자.
1
2
3
4
5
6
(define (abs x)
(if (< x 0)
(- x) ; x < 0이 참이라면 -x 반환
x ; x <0이 거짓이라면 x 반환
)
)
list, vector
list
는 흔히 대부분 언어에서 사용하는array
와 유사한 데이터 형식이다.racket
의list
의 특이한 점은linkedlist
자료구조랑 비슷하다.- 목록은 요소 두 개짜리 쌍으로 구현하는
1
2
3
4
5
6
7
(define a-list (list 6 946 8 356 12 620))
a-list
(6 946 8 356 12 620)
(list? a-list)
#t true
(list? 3)
#f false
1
2
3
4
5
6
(cons a b) ; 인수 두 개만 사용되며 (a b) 리스트를 생성한다.
(define a-pair (cons 1 2)) ; a-pair = (1 2)
(car a-pair) ; car는 가장 앞의 요소를 반환한다.
1
(cdr a-pair) ; cdr는 car 요소를 제외한 나머지 요소들을 반환한다.
2
책의 예제에는 안 나와서 cons a-list 1
와 같이 list
와 숫자 리터럴 순서로 넣으면 어떻게 되는지 궁금해서 직접 실행해봤다. 그랬더니 car
로 호출되는 요소는 a-list
통째로 나왔다.
- vector는 우리에게 좀 더 친숙한 배열의 느낌의 데이터 형식이다.
vector-ref
키워드는 배열의 인덱스 접근하는 방식으로 쓰면 된다.
1
2
3
4
5
(define a-vector (vector 1 2 3 4))
a-vector
#(1 2 3 4) ; 출력결과는 #붙는다.
(vector-ref a-vector 2) ;a-vector[2]
3
이 다음 글이 날아가서 다음시간에 본격적으로 책 초반을 어떻게 이해해 나가야할지 알아보자.. ■
- 다음 글 : 유연한 프로그래밍을 위한 설계원칙 조금 살펴보기
Reference
상수형 변수보면 메모리 주소와 데이터 값이 있는데 리터럴은 주소가 아닌 데이터 값 그 자체를 말한다. ↩︎