12. FPL (1)
Functional Programming Languages
What do we study in this chapter?
- Introduction
- Mathematical Functions
- Fundamentals of Functional Programming Languages
- The First Functional Programming Language: Lisp Introduction to Scheme
- Common Lisp
- ML
- Haskell
- F#
- Support for Functional Programming in Primarily Imperative Languages
- Comparison of Functional and Imperative Languages
Introduction
The design of imperative language
- Based on von Neumann architecture
- ์ด ๊ตฌ์กฐ์์๋ ํ๋ก๊ทธ๋จ๊ณผ ๋ฐ์ดํฐ๊ฐ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ๋๊ณ , ํ๋ก์ธ์๊ฐ ๋ช ๋ น์ด๋ฅผ ์์ฐจ์ ์ผ๋ก ์คํํจ
- Primary concern: efficiency (rather than suitability for SW development)
- ์ด๊ธฐ ๋ช ๋ นํ ์ธ์ด์ ๋ชฉ์ ์ ๊ฐ๋ฐ์์ ํธ์์ฑ๋ณด๋ค ์คํ ํจ์จ์ฑ์ ์ฐ์ ์
- ํ๋์จ์ด ์์์ ์ต๋ํ ํจ์จ์ ์ผ๋ก ์ฐ๋ ๊ฒ์ด ์ค์ํ๊ธฐ ๋๋ฌธ์, ์ง๊ด์ ์ด์ง ์์ ์ ์์ค ์ฐ์ฐ์ด ๋ง๊ณ , ์๋ฌ ์ ๋ฐ ๊ฐ๋ฅ์ฑ๋ ๋์
- Reliance on the underlying architecture is thought by some to be an unnecessary restriction
- Uses of variables are important
- How program's state change
- ๋ณ์ ๊ฐ์ด ๋ฐ๋๋ฉด์ ์ํ๊ฐ ๋ณํ๋ฏ๋ก, ํฐ ํ๋ก๊ทธ๋จ์์๋ ์ํ์ ํ๋ฆ์ ์ถ์ ํ๋ ๊ฒ์ด ๋งค์ฐ ์ด๋ ต๊ณ ๋ณต์กํด์ง
- โ This is a daunting task for a large program
The design of functional language
- Based on mathematical functions
- ์ ๋ ฅ โ ํจ์ โ ์ถ๋ ฅ์ ๊ด๊ณ๋ก, ์ํ ๋ณ๊ฒฝ ์์ด ๊ฒฐ๊ณผ๋ฅผ ๊ณ์ฐํ๋ ๊ฒ์ด ํต์ฌ
- Solid theoretical basis (oriented more to particular programming paradigms or methodologies than to efficiency)
- ํจ์ํ ์ธ์ด๋ ๋๋ค ๊ณ์ฐ๋ฒ(-calculus) ๊ฐ์ ์ด๋ก ์ ๊ธฐ๋ฐ์ด ํผํผ
- ํจ์จ์ฑ๋ณด๋ค ๋ช ํํ ํจ๋ฌ๋ค์(๋ชจ๋์ฑ, ๋ถ๋ณ์ฑ, ์ฌ๊ท ๋ฑ)์ ์ด์ ์ ๋
- Closer to user (relatively less concerned with machine architecture)
- ํจ์ํ ์ธ์ด๋ ๊ธฐ๊ณ์ ์๋ ๋ฐฉ์์ ๋ ์์กดํ๊ณ , ๊ฐ๋ฐ์์ ์ฌ๊ณ ํ๋ฆ์ ๋ ๊ฐ๊น์
- ๋ช ๋ นํ ์ธ์ด์ฒ๋ผ ์ํ(state)๋ฅผ ์ถ์ ํ์ง ์์๋ ๋จ
- LISP: began as pure functional language (1950๋ ๋ ๊ฐ๋ฐ)
- But, acquired some important imperative features
- ๋ช
๋ นํ ํน์ฑ(๋ฃจํ, ๋ณ์ ํ ๋น ๋ฑ, (ex.)
set!,loop,progn) - Used in knowledge representation, machine learning, intelligent training systems, and the modeling of speech
- Common LISP is a dialects of LISP (๋ค์ํ LISP ๋ฐฉ์ธ์ ํตํฉํ ํ์คํ๋ ๋ฒ์ )
- Scheme is a small, static-scoped dialect of LISP
- ML, Haskell, OCaml, and F#: typed functional programming languages
Mathematical Functions
Mapping member of domain(์ ์์ญ) set to range(์น์ญ) set
- Function definition specifies domain and range sets
- Along with mapping described by expression or table
- Functions are applied to elements of domain set to yield elements of range set
- Fundamental characteristics of mathematical functions
- Evaluation order is controlled by recursion and conditional expressions
- Rather than sequencing and iterative repetition
- ๋ช
๋ นํ ์ธ์ด์ฒ๋ผ
for,while๊ฐ์ ๋ฐ๋ณต๋ฌธ์ ์์กดํ์ง ์์ - No side effects and cannot depend on any external values
- ๊ฐ์ ์ ๋ ฅ์ ๋ํด ํญ์ ๊ฐ์ ์ถ๋ ฅ โ ์ฐธ์กฐ ํฌ๋ช ์ฑ(referential transparency) ๋ณด์ฅ
- No concept of stage of function
- ๋ช ๋ นํ ์ธ์ด์ฒ๋ผ ํจ์๊ฐ ์ค๊ฐ ์ํ(stage)๋ฅผ ๊ฐ์ง ์์
- ํจ์๋ ๊ทธ ์์ฒด๋ก ์๊ฒฐ๋ ๊ณ์ฐ ๋จ์์ด๋ฉฐ, ์ด์ ์ํ๋ฅผ ๊ธฐ์ตํ์ง ์์
Function definitions are written
- Name, list of parameters in parentheses and mapping expression
- โํจ์ ์ด๋ฆ + ๊ดํธ ์ ๋งค๊ฐ๋ณ์ + ์ ์ ์์โ์ ํํ๋ก ์ ์๋จ
- [EX]
cube(x) โก x * x * x โก: โis defined asโ (cube๋ ํจ์ ์ด๋ฆ, x๋ ๋งค๊ฐ๋ณ์(parameter), x * x * x๋ ํจ์๊ฐ ์ํํ๋ ๊ณ์ฐ์ ๋ํ๋) (์ํ์ ์ผ๋ก "โฆ๋ก ์ ์๋๋ค"๋ฅผ ์๋ฏธํจ)- Parameter x can be any member of domain set but fixed during evaluation
- ํ๊ฐ ๊ณผ์ ์์๋ ๊ณ ์ ๋จ โ ํน์ ๊ฐ์ผ๋ก ๋ฐ์ธ๋ฉ(binding) ๋จ
- [EX]
cube(2.0) = 2.0 * 2.0 * 2.0 = 8 - x is bound to 2.0 during the evaluation and there are no unbound parameters
- ํ๊ฐ ์ค์๋ ๋ชจ๋ ๋ณ์๋ค์ด ๊ฐ์ ๋ฌถ์ฌ ์์ผ๋ฉฐ, ๋ฐ๋ผ์ ๋ช ํํ๊ณ ์์ธก ๊ฐ๋ฅํ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฅํจ
Early theoretical work on functions separated the task of defining a function from that of naming the function โ ํจ์๋ฅผ ์ ์ํ ์ ์์ง๋ง ๊ผญ ์ด๋ฆ์ ๋ถ์ผ ํ์๋ ์๋ค๋ ๊ฐ๋ ์ด ์๊น โ nameless function
- Lambda expression specifies parameter(s) and mapping functions
- [EX] ((๋ณ์) ์) vs
cube(x) โก x * x * x(์ด๋ฆ ์์) - ์ ๊น ์ธ ํจ์์ธ๋ฐ ๊ตณ์ด ์ด๋ฆ ๋ถ์ด๊ธฐ ์ซ์ ๋
numbers = [1, 2, 3]doubled = map(lambda x: x * 2, numbers)# ํจ์ ์ด๋ฆ ์์ด ์ฌ์ฉ- ๋ค๋ฅธ ํจ์์ ํจ์๋ฅผ ์ ๋ฌํ ๋
- ์ด๋ฆ ์์ด ํจ์๋ฅผ ๋ฐ๋ก ์ ์ํด์ ์ ๋ฌ ๊ฐ๋ฅ
- ํจ์๊ฐ ์ผํ์ฑ์ผ ๋ ๋งค์ฐ ์ ์ฉ
Formal computation model using lambda expressions โ lambda calculus
- โ๊ณ์ฐ์ ํจ์๋ก๋ง ํํํ์โ๋ ์ํ์ ๋ชจ๋ธ
- ๋ชจ๋ ๊ณ์ฐ์ ํจ์ ์ ์์ ์ ์ฉ์ผ๋ก ์ค๋ช ํ ์ ์๋ ์ด๋ก ์ ๊ธฐ์ด ์ ๊ณต
- โ "๊ณ์ฐ์ด๋ผ๋ ๊ฑด ๊ฒฐ๊ตญ, ์ด๋ค ๊ฐ์ ํจ์์ ๋ฃ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ์ป๋ ๊ณผ์ ์ผ ๋ฟ์ด๋ค."
- ๋ชจ๋ ๊ณ์ฐ์ ๋ค์ ๋ ๊ฐ์ง๋ง์ผ๋ก ์ค๋ช ํ๋ ค๊ณ ํจ
- ํจ์๋ฅผ ์ ์ํ๊ธฐ
- ๊ทธ ํจ์์ ๊ฐ์ ์ ์ฉํ๊ธฐ
- ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ์ด๋ก ์ ๋ฟ๋ฆฌ
- Can be typed or untyped
- Untyped lambda calculus: ๋ชจ๋ ํํ์ ์์ ๋กญ๊ฒ ์ฌ์ฉ
- Typed lambda calculus: ํ์ ์ ์ฝ ์กด์ฌ (โ Haskell, ML ๋ฑ ํจ์ํ ์ธ์ด๋ก ๋ฐ์ )
Are applied to parameter(s) by placing the parameter(s) after the expression
- [EX]
= 8- ๋ ์ต๋ช ํจ์
(2)๋ ์ธ์ ์ ์ฉ(application)
Functional forms
A higher-order function, or functional form
- ํจ์๋ ์ซ์์ฒ๋ผ ๋ค๋ฃฐ ์ ์๋ค๋ฉดโฆ ๊ณ ์ฐจํจ์
- Takes functions as parameters
- Yields a function as its result
- Or both above
- ๊ณ ์ฐจ ํจ์๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ํต์ฌ ๋๊ตฌ
- ์ฝ๋๋ฅผ ๋ ์ ์ฐํ๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ๋ง๋ฆ
Functional composition
- A functional form that takes two functions as parameters
- Yields a function whose value is the first actual parameter function
- applied to the application of the second
- [EX] Form:
h โก f ห g(หis operator for function composition) - means
h(x) โก f(g(x)) - for
f(x) โก x + 2,g(x) โก 3*x,h โก f ห gyields(3*x) + 2
def compose(f, g):
return lambda x: f(g(x))
def square(x): return x * x
def add_one(x): return x + 1
new_func = compose(square, add_one)
print(new_func(3)) # ๊ฒฐ๊ณผ: square(add_one(3)) โ square(4) = 16
Apply-to-all
- A functional form that takes a single function as a parameter
- Yields a list of values obtained by applying the given function to each element of a list of parameters
- Form:
- For
h(x) โก x * x - yields
(4, 9, 16)
def h(x):
return x * x
numbers = [2, 3, 4]
result = list(map(h, numbers))
print(result) # [4, 9, 16]
# with ๋๋ค ํํ์
result = list(map(lambda x: x * x, [2, 3, 4]))
Fundamentals of Functional Programming Languages
Objective of design of FPL
- Mimic mathematical functions
- ์ ๋ ฅ์ด ์ฃผ์ด์ง๋ฉด ํญ์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๊ณ ์ค๊ฐ ์ํ๋ ๋ณ์ ์์ด ๊ณ์ฐ์ด ์ด๋ค์ง โ ์์ธก ๊ฐ๋ฅํ๊ณ ์์ ํ ๊ณ์ฐ
- The basic process of computation is fundamentally different from imperative language
- In imperative
- ์ปดํจํฐ์๊ฒ "์ด๋ป๊ฒ(how)" ๊ณ์ฐํ ์ง ๋ช ๋ น์ ๋ด๋ฆฌ๋ ๋ฐฉ์
- Operations are done โ results are stored in variables
- Management of variable is concern and course of complexity
- [EX]
(x+y)/(a-b) - Value of
(x+y)is computed and stored while(a-b)is evaluated - In FPL
- "๋ฌด์์(what)" ๊ณ์ฐํ ์ง๋ฅผ ์ ์ธ(declare)ํ๋ ๋ฐฉ์
- ๊ณ์ฐ ์์๋ ์ค๊ฐ ๋ณ์์ ์ ๊ฒฝ ์ฐ์ง ์๊ณ , ๋ชจ๋ ๊ฒ์ด ํํ์(expression)์ผ๋ก ๊ตฌ์ฑ๋จ
- [EX]
(x+y)/(a-b) - ๋ณ์ ๊ฐ์ด ์ฃผ์ด์ง๋ฉด, ๋ด๋ถ์ ์ผ๋ก ๊ณ์ฐ์ด ์๋์ผ๋ก ์งํ๋จ ์ค๊ฐ ์ํ ์์ด, ๊ฒฐ๊ณผ๋ง ๋ฐํ๋จ
- Variables and assignments are not necessary (as in math)
- ์ํ์์
x = 3๋ผ๊ณ ํ๋ฉด,x๋ ์ ๋ ๋ฐ๋์ง ์๋ ๊ฐ - ๋ฐ๋ฉด ๋ช
๋ นํ ์ธ์ด์์
x = x + 1๊ฐ์ ๋ฌธ์ฅ์ด ๊ฐ๋ฅ - ํจ์ํ ์ธ์ด์์ ๊ฐ์ด ํ ๋ฒ ์ ํด์ง๋ฉด ์ ๋ ๋ฐ๋์ง ์์ โ ๋ณ์๊ฐ ์๋๋ผ ์์์ ๊ฐ๊น์
- โ Freeing programmer from concerns of memory cells
- Iterative construct โ recursion
- ์ํ(state)๋ฅผ ๋ฐ๊พธ๋ ๋ฐ๋ณต ๋์ ์์ํ ํจ์ ํธ์ถ๋ก ํด๊ฒฐ
- Referential Transparency - Evaluation of a function always produces the same result given the same parameters
- ๊ฐ์ ์ ๋ ฅ โ ํญ์ ๊ฐ์ ์ถ๋ ฅ
- ์ธ๋ถ ์ํ์ ์ํฅ์ ๋ฐ์ง ์์ = ์์ ํจ์
- ์ด๋ฐ ์ฑ์ง์ด ์์ผ๋ฉด ๋๋ฒ๊น ์ด ํจ์ฌ ์ฝ๊ณ , ํ ์คํธ๋ ๊ฐ๋จํจ
- Makes semantics of FPL far simpler than imperative
- ๋ณ์ ๋ณํ ์์, ์์ ํจ์๋ง ์กด์ฌ, ์ํ๋ ์์
- A set of primitive functions are provided (smaller number is good)
- FPL์ ๋ณดํต ์ ์ ์์ ๊ธฐ๋ณธ ํจ์๋ง ์ ๊ณตํ๊ณ , ๊ทธ๊ฑธ ์กฐํฉํด์ ๋ณต์กํ ๋์์ ๋ง๋ค๊ฒ ์ ๋ํจ.
Original Lisp
The first functional language
- LISt Processing์ ์ค์๋ง โ ๋ฆฌ์คํธ ๊ธฐ๋ฐ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๋ค๋ฃจ๊ธฐ ์์ฃผ ์ข์
- No longer represents the latest design concepts for functional languages
- Represent well the fundamental concepts of functional programming
- LISP๋ ๋๋ค ํํ์, ์ฌ๊ท, ํจ์ ์์ฒด๋ฅผ ๊ฐ์ฒ๋ผ ๋ค๋ฃจ๋ ๋ฐฉ์ ๋ฑ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ํต์ฌ ๊ฐ๋ ์ ๋ด๊ณ ์์
- Therefore worthy of study
- All LISP dialects include imperative-language features
- Imperative-style variables, assignment statements, and iteration
Lisp Data Types and Structures
Data object types: originally only atoms and lists
- (1) Atom (์์): ์ชผ๊ฐค ์ ์๋ ๋จ์ผ ๊ฐ
- ์ซ์, ๊ธฐํธ(symbol), ๋ฌธ์ ๋ฑ์ด ํฌํจ
- ์:
A,42,'helloโ - (2) List (๋ฆฌ์คํธ)
- ๊ดํธ๋ก ๋๋ฌ์ธ์ธ ์์์ ๋ฆฌ์คํธ์ ์งํฉ
- ๋ฆฌ์คํธ ์์๋ ๋ค๋ฅธ ๋ฆฌ์คํธ๋ ํฌํจ๋ ์ ์์ด (์ค์ฒฉ ๊ฐ๋ฅ)
- List form: parenthesized collections of sublists and/or atoms
- [EX]
(A (B C) D (E (F G))) - ์ฒซ ๋ฒ์งธ ์์:
A(atom) - ๋ ๋ฒ์งธ:
(B C)(sublist) - ์ธ ๋ฒ์งธ:
D(atom) - ๋ค ๋ฒ์งธ:
(E (F G))(sublist ์์ ๋ sublist)
Originally, Lisp was a typeless language
- ์ด๊ธฐ Lisp์์๋ ๋ชจ๋ ๊ฐ์ด ๋ฆฌ์คํธ ๋๋ atom์ผ๋ก ํํ๋จ
- ์ ์, ๋ฌธ์์ด, ๋ถ๋ฆฌ์ธ ๊ฐ์ ํ์ ๊ตฌ๋ถ์ด ๋ช ํํ์ง ์์์
- ๋์ค์ Common Lisp ๋ฑ์์ ๋ค์ํ ํ์
์ด ์ถ๊ฐ๋จ (์:
integer,float,string๋ฑ) - Lisp lists are stored internally as singlelinked lists
(A B C)[A] โ [B] โ [C] โ NIL
Lisp Interpretation
The first requirement for the universal LISP function
- The first Lisp interpreter appeared only as a demonstration of the universality of the computational capabilities of the notation
- Lisp์ ํต์ฌ ์ฒ ํ ์ค ํ๋์ธ ์ฝ๋์ ๋ฐ์ดํฐ์ ๋์ผํ ํํ (Code-as-Data)
- Notation allowing functions to be expressed in the same way data expressed
- [EX]
(A B C), [ex](+ 2 3); โ 5 - [1] ๋ฐ์ดํฐ๋ก ํด์: Can be interpreted as a simple list of three atoms
- ์์ A, B, C๊ฐ ๋ค์ด ์๋ ๋ฆฌ์คํธ
- [2] ์ฝ๋๋ก ํด์: Can be interpreted as if function named A is applied to two parameters
- ํจ์ A๊ฐ B์ C๋ฅผ ์ธ์๋ก ๋ฐ์ ํธ์ถ๋๋ ๊ฒ
- ์ฝ๋๋ ๋ฐ์ดํฐ์ฒ๋ผ
- ํ๋ก๊ทธ๋จ์ด ์๊ธฐ ์์ ์ ๋ถ์ํ๊ฑฐ๋ ์์ ํ ์ ์์ โ ๋ฉํํ๋ก๊ทธ๋๋ฐ ๊ฐ๋ฅ
(eval '(+ 1 2))- ์ปดํ์ผ๋ฌ, ์ธํฐํ๋ฆฌํฐ, ๋งคํฌ๋ก ์์คํ ๋ฑ์ ์ธ์ด ๋ด๋ถ์์ ๊ตฌํํ ์ ์์
Specified in a prefix list form (Cambridge Polish or Cambridge prefix)
- ์์์ด๋ ํจ์ ํธ์ถ์ ํญ์ ์์์๋ถํฐ ์ฝ์
(function_name argument1 โฆ argumentn)- ์์ ํจ์ ์ด๋ฆ์ด ์ค๋ ํ์(prefix)์ ์
(+ 5 7)(+ 3 4 7 6)- Lambda notation is used to specify functions and function definitions
- ํจ์๋ฅผ ๋ง๋ค ๋ LAMBDA๋ผ๋ ํค์๋๋ฅผ ์ฌ์ฉ
(function_name (LAMBDA (arg1 ... argn) expression))- ์ด๊ฑด "์ด๋ฆ์ด ์๋ ํจ์"๋ฅผ ์ ์ํ๋ ๋ฐฉ์
(define square (lambda (x) (* x x)))- square๋ผ๋ ์ด๋ฆ์ ํจ์ ์ ์
(lambda (x) (* x x))โ x๋ฅผ ๋ฐ์์ x * x๋ฅผ ๊ณ์ฐํ๋ ํจ์((lambda (x) (* x x)) 5); โ 25- ์ด๋ฆ ์๋ ํจ์๋ ๊ฐ๋ฅ
- ํจ์์ ์ด๋ฆ ์์ด ๋ฐ๋ก ์ ์ํ๊ณ , 5๋ฅผ ๋ฃ์ด ์คํํจ
All LISP structures, both data and code, were called S-expression
- S-expressions became LISPโs only notation
- ๊ดํธ๋ก ๋๋ฌ์ธ์ธ ๋ฆฌ์คํธ ๊ตฌ์กฐ
- ์ด ์์ ๋ฐ์ดํฐ๋ ํจ์ ํธ์ถ์ด๋ ๋ค ํํ
(+ 2 3); ํจ์ ํธ์ถ, ์คํ ๊ฐ๋ฅํ ํจ์ ํธ์ถ(A (B C) D); ๋ฐ์ดํฐ ๋ฆฌ์คํธ, ๋จ์ํ ๋ฆฌ์คํธ ๋ฐ์ดํฐ
McCarthy successfully developed a universal function (EVAL) that could evaluate any other function
- ์ด๋ค ์ฝ๋๋ ์คํํ ์ ์๋ ํจ์
- Implementation of EVAL could serve as a LISP interpreter
- EVAL์ S-expression์ ๋ฐ์์ ์ค์ ๋ก ์คํ์ํด
- Lisp ์ฝ๋ ์์ฒด๋ฅผ ์ ๋ ฅ๊ฐ์ผ๋ก ๋ฐ์ ์ฒ๋ฆฌํจ
(eval '(+ 2 3)); โ 5- ์กด ๋งค์นด์(John McCarthy)๋ ์ด EVAL ํจ์ ํ๋๋ก ๋ชจ๋ Lisp ํ๋ก๊ทธ๋จ์ ์คํํ ์ ์๊ฒ ๋ง๋ฆ โ Lisp ์ธํฐํ๋ฆฌํฐ ์์ฒด๋ฅผ Lisp๋ก ๊ตฌํํ ์ ์๊ฒ ๋จ
- Before 1975, dialects of LISP are dynamic scoping
- Contemporary dialects use static scoping or can choose static or dynamic.
Origins of Scheme
A mid-1970s dialect of Lisp, designed to be a cleaner, more modern, and simpler version than the contemporary dialects of Lisp
- Uses only static scoping (์ด์ Lisp์ ๋์ ์ค์ฝํ ์ฌ์ฉ)
- Functions are first-class entities
- A first-class object refers to an object that supports all operations that are generally applicable to other objects
- They can be the values of expressions and elements of lists
- They can be assigned to variables, passed as parameters, and returned from functions
The Scheme Interpreter
Scheme์ ์ธํฐํ๋ฆฌํฐ ๋์ ๋ฐฉ์
- In interactive mode, the Scheme interpreter is an infinite read-evaluate-print loop (REPL)
- โ Read (์ฝ๊ธฐ) โ Eval (ํ๊ฐ) โ Print (์ถ๋ ฅ) โ ๋ฐ๋ณต
- โ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ์(expression)์ ์ฝ๊ณ , ํ๊ฐํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํ ๋ค ๋ค์ ๋๊ธฐ
- This form of interpreter is also used by Python and Ruby (ํ๋ ์คํฌ๋ฆฝํธ ์ธ์ด)
- Expressions are interpreted by the function EVAL (์ฃผ์ด์ง ์์ ํด์ํ๊ณ ์คํํ๋ ๊ธฐ๋ฅ)
- Literals evaluate to themselves
- If typing a number to interpreter โ simply display the number
- EVAL์ Scheme ๋ด๋ถ์์ ํํ์์ ๋ฐ์ ์คํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ํจ์
- Scheme์์๋ ์ฝ๋๋ ์ผ์ข ์ ๋ฆฌ์คํธ ๊ตฌ์กฐ(S-expression)์ด๊ธฐ ๋๋ฌธ์, ๋ฆฌ์คํธ๋ก ํํ๋ ์ฝ๋๋ฅผ ๊ทธ๋๋ก ์คํ์ํฌ ์ ์์
> (eval '(+ 2 3))5- ๋ณดํต์ ์ง์ eval์ ์์ฃผ ์ฐ์ง ์์ง๋ง, ๋ค์๊ณผ ๊ฐ์ ์ํฉ์์ ์ ์ฉ
- ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ๋ฌธ์์ด์ ์ฝ๋๋ก ์คํํ๊ณ ์ถ์ ๋
- ๋ฉํํ๋ก๊ทธ๋๋ฐ (์ฝ๋๋ฅผ ์กฐ์ํ๋ ์ฝ๋)์ ๊ตฌํํ ๋
- REPL์ ๊ตฌํํ ๋ (eval์ด ํต์ฌ ํจ์)
Primitive Function Evaluation
Primitive Function Evaluation์ ๊ณผ์
- [์ธ์ํ๊ฐ] Parameters are evaluated, in no particular order
- โ ์ธ์ ๊ฐ ๋ถ์์ฉ(side effect)์ด ์๋ค๋ฉด ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง ์ ์์
- โ ์์ ํจ์ ์ฌ์ฉ์ด ๊ถ์ฅ๋จ
- [์ ๋ฌ] The values of the parameters are passed into the function body
- ์ ๋ฌ๋ ์ธ์ ๊ฐ์ ์ด์ฉํด ํจ์ ๋ก์ง ์ํ
- [๋ถ๋ฌธ ์คํ] The function body is evaluated
- [๋ฐํ] The value of the last expression in the body is the value of the function
- Scheme์์๋ ๋ง์ง๋ง ์์ ๊ฒฐ๊ณผ๊ฐ์ด ์ ์ฒด ํจ์์ ๋ฐํ๊ฐ
Primitive Functions & LAMBDA Expressions
Primitive Arithmetic Functions: +, -, * , /, MODULO, ROUND, MAX, MIN, LOG, SIN, and SQRT
- ์ ๋(prefix) ํ๊ธฐ๋ฒ์ ์ฌ์ฉ
- If no parameters are given for
*, 1 is returned (๊ณฑ์ ์ ํญ๋ฑ์) - If no parameters are given to
+, 0 is returned (๋ง์ ์ ํญ๋ฑ์) - Use uppercase letters for all reserved words and predefined functions
| Expression | Value | Expression | Value |
|---|---|---|---|
| 42 | 42 | (SQRT 9) | 3.0 |
(* 3 7) | 21 | (MODULO 17 5) | 2 |
(+ 5 7 8) | 20 | (ROUND 3.6) | 4 |
(โ 5 6) | โ1 | (MAX 3 8 2 9 1) | 9 |
(โ 15 7 2) | 6 | (MIN 3 8 2 9 1) | 1 |
(โ 24 (* 4 3)) | 12 | (SIN (/ PI 2)) | 1.0 |
Lambda Expressions
- Nameless function actually includes the word LAMBDA
- Form is based on notation
- [EX]
(LAMBDA (x) (* x x)) - ์ด ์ ์์ฒด๋ ํจ์ ๊ฐ์ฒด(function object)๋ฅผ ๋ฐํ
- Lambda expressions can be applied to parameters
- [EX]
((LAMBDA (x) (* x x)) 7) - x is called a bound variable (never change after being bound)
- Lambda expressions can have any number of parameters
- [EX]
(LAMBDA (a b x) (+ (* a x x) (* b x)))
Special Form Function: DEFINE
DEFINE - Two forms:
- The evaluation process (interpreted by EVAL) for DEFINE is different!
- [1] To bind a symbol to an expression (์ด๋ค ์ด๋ฆ์ ๊ฐ์ "์ ์"ํ๋ ๋ฐฉ์)
- [EX]
(DEFINE pi 3.141593) - pi๋ 3.141593์ ๋ฐ์ธ๋ฉ๋จ
- [EX of use]
(DEFINE two_pi (* 2 pi)) - two_pi๋ (* 2 pi)์ ํ๊ฐ ๊ฒฐ๊ณผ์ธ 6.283186์ ๋ฐ์ธ๋ฉ๋จ
- These symbols are not variables โ they are like the names bound by Javaโs
finaldeclarations - โ ๋ค์ DEFINEํ์ง ์๋ ์ด์ ๋ณ๊ฒฝ ๋ถ๊ฐ
- [2] To bind names to lambda expressions (LAMBDA is implicit)
- ์ด ๊ฒฝ์ฐ LAMBDA๊ฐ ์๋ฌต์ ์ผ๋ก ํฌํจ๋จ
- [EX]
(DEFINE (square x) (* x x))โ(DEFINE square (LAMBDA (x) (* x x))) - [EX of use]
(square 5) - The first parameter is never evaluated
- The second parameter is evaluated and bound to the first parameter
Output Functions
Usually not needed
- Because interpreter always displays the result of a function evaluated at the top level (not nested)
- ๋จ, ์ด๊ฑด ์ต์์ ์์ค์์๋ง ํด๋น๋จ. ํจ์ ๋ด๋ถ์์ ์ถ๋ ฅ์ ์ํ ๊ฒฝ์ฐ ๋ช ์์ ์ถ๋ ฅ ํจ์๊ฐ์ด ํ์ํจ
- Scheme has
PRINTF, which is similar to theprintffunction of C - ๋๋ถ๋ถ์ ํ์ค Scheme์๋ ์๊ณ , ์ผ๋ถ ๊ตฌํ์์๋ง ์ง์
Display and Read Functions
DISPLAY function: simply prints the arguments
(DISPLAY 21)21(DISPLAY "hello")hello
READ function: enter what we type on the keyboard
(DEFINE x (READ))7
Numeric Predicate Functions
A predicate function is one that returns a Boolean value
#T(or#t) is true and#F(or#f) is false(= 3 3); โ#t(< 3 5); โ#t(> 7 10); โ#f- Sometimes
()is used for false - ์ฃผ์ ํ๋ณ ์ฐ์ฐ์ (
=,<>,>,<,>=,<=) - ์ซ์ ๊ด๋ จ ํ๋ณ ํจ์ (
EVEN?,ODD?,ZERO?,NEGATIVE?) - Notice that the names for all predefined predicate functions that have words for names end with question marks
- The NOT function inverts the logic of a Boolean expression
(NOT #t); โ#f(NOT #f); โ#t(NOT (EVEN? 3)); โ#t(DEFINE x 11)(= x 11)returns#T(> x 11)returns()(< x 15)return#T(EVEN? x)returns()(ODD? x)returns#T
Control Flow
Selection- the special form, IF (two-way selector function)
(IF predicate then_exp else_exp)
(IF (> 3 2) 'yes 'no)
; returns yes
(DEFINE x 7)
(DEFINE y 10)
(IF (> x y)
(- x y)
(- y x))
; returns 3
(DEFINE (test x)
(IF (>= x 70)
(DISPLAY "pass")
(DISPLAY "fail")))
(test 75) ; returns pass
(DEFINE (factorial n)
(IF (<= n 1)
1
(* n (factorial (โ n 1)))))
Recall from Chapter 8 the COND function (multiple selection):
(DEFINE (admissionfee age)
(COND
((<= age 6) 0)
((< age 60) 5000)
(ELSE 2500)))
(admissionfee 65) ; returns 2500
(DEFINE (leap? year)
(COND
((ZERO? (MODULO year 400)) #T)
((ZERO? (MODULO year 100)) #F)
(ELSE (ZERO? (MODULO year 4)))))
(leap? 2024) ; returns #T
List Functions
QUOTE - takes one parameter; returns the parameter without evaluation
- QUOTE is required because the Scheme interpreter, named EVAL, always evaluates parameters to function applications before applying the function
- QUOTE is used to avoid parameter evaluation when it is not appropriate
- ํ๊ฐ๋ฅผ ๋ง๊ณ , ์๋ ๋ชจ์ ๊ทธ๋๋ก ๋๊น
- QUOTE can be abbreviated with the apostrophe prefix operator
'(A B)is equivalent to(QUOTE (A B))- ๋ง์ฝ QUOTE ์์ด ๊ทธ๋ฅ
(A B)๋ฅผ ์ฐ๋ฉด, Scheme์ A๋ผ๋ ํจ์๋ฅผ B์ ์ ์ฉํ๋ ค๊ณ ์๋ํจ โ ์ค๋ฅ ๋ฐ์ ๊ฐ๋ฅ - Recall that CAR, CDR, and CONS were covered in Chapter 6
CAR and CDR operations:
(CAR '(A B C))returnsA(CAR โฒ((A B) C D))returns(A B)(CAR โฒA)is an error because A is not a list(CAR '(A))returnsANames lies in the first implementation (IBM 704) of LISP
IBM 704๋ ํ๋์ ๋ ์ง์คํฐ๋ฅผ ๋ ๊ฐ์ ํ๋๋ก ๋๋์ด ์ฌ์ฉ
CAR (contents of the address part of a register) - ํค๋๋ฅผ ํํ
CDR (contents of the decrement part of a register) - ๊ผฌ๋ฆฌ๋ฅผ ํํ
(CAR '())is an error(CDR '(A B C))returns(B C)(CDR โฒ((A B) C D))returns(C D)(CDR โฒA)is an error(CDR โฒ(A))returns()(CDR '())is an error
Combine CAR and CDR
(DEFINE (second a_list) (CAR (CDR a_list)))(second '(A B C))returnsB- [ํจ์ ํฉ์ฑ ์ถ์ฝํ (Built-in Compositions)] Some of the most commonly used functional compositions in Scheme are built in as single functions
(CAAR x)is equivalent to(CAR(CAR x))(CADR x)is equivalent to(CAR (CDR x))(CADDAR x)is equivalent to(CAR (CDR (CDR (CAR x))))
CONS: inverse of CAR and CDR
- Two parameters to CONS: CAR and CDR of the new list
(CONS (CAR a_list) (CDR a_list))returnsa_list(CONS 'A '())returns(A)(CONS 'A '(B C))returns(A B C)(CONS โฒ() โฒ(A B))returns(() A B)(CONS โฒ(A B) โฒ(C D))returns((A B) C D)
LIST is a function for building a list from any number of parameters
(LIST โฒapple โฒorange โฒgrape)returns(apple orange grape)= (CONS 'apple (CONS 'orange (CONS 'grape '())))- ๋ด๋ถ์ ์ผ๋ก๋ CONS๋ฅผ ์ฌ๋ฌ ๋ฒ ์ค์ฒฉํด์ ๋ฆฌ์คํธ๋ฅผ ๋ง๋๋ ๊ฒ๊ณผ ๊ฐ์
Predicate Function
Predicate Function: EQ? (๊ฐ์ฒด์ ๋์ผ์ฑ(identity)์ ๋น๊ต)
- EQ? takes two expressions as parameters (usually two atoms);
- It returns #T if both parameters have the same pointer value; otherwise #F
- ๋ ๊ฐ์ฒด๊ฐ ๋์ผํ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์(= ํฌ์ธํฐ)๋ฅผ ์ฐธ์กฐํ๋๊ฐ๋ฅผ ๊ฒ์ฌ
(EQ? 'A 'A)yields#T(EQ? 'A 'B)yields#F(EQ? 'A '(A B))yields#F(EQ? '(A B) '(A B))yields#Tor#F- ์๋ก ๊ตฌ์กฐ๊ฐ ๊ฐ์๋ ๋ค๋ฅธ ๊ฐ์ฒด์ผ ์ ์์ (๋ฆฌ์คํธ๋ ๋งค๋ฒ ์๋ก ์์ฑ๋จ)
(EQ? 3.4 (+ 3 0.4))yields#Tor#F- ๋ถ๋์์์ ์ฐ์ฐ ๊ฒฐ๊ณผ๊ฐ ๋ด๋ถ์ ์ผ๋ก ๊ฐ์๋ ๊ฐ์ฒด๋ ๋ค๋ฅผ ์ ์์
Predicate Function: EQV?
- EQ? works for symbolic atoms but does not necessarily work for numeric atoms
=predicate works for numeric atoms but not symbolic atoms- ๊ฐ(value)์ด ๊ฐ์์ง๋ฅผ ๋น๊ตํ๋ predicate ํจ์
- EQV? is like EQ?, except that it works for both symbolic and numeric atoms
- EQ?์ ๋น์ทํ์ง๋ง, ๋ ์ ์ฐํ๊ณ ๋์ ๋ฒ์์ ํ์ ์ ๋ํด ์ ์๋
- It is a value comparison, not a pointer comparison
(EQV? 3 3)yields#T(EQV? 'A 3)yields#F(EQV 3.4 (+ 3 0.4))yields#T(EQV? 3.0 3)yields#F(floats and integers are different)- Primary reason to use EQ? or
= - Faster than EQV?
Predicate Functions: LIST? and NULL?
- LIST? takes one parameter;
- It returns #T if the parameter is a list; otherwise #F
- x๊ฐ ๋ฆฌ์คํธ์ธ์ง ํ์ธ
(LIST? '(X Y))returns#T(LIST? 'X)returns#F; ๋จ์ ์ฌ๋ณผ(LIST? '())yields#T; ๋น ๋ฆฌ์คํธ๋ ๋ฆฌ์คํธ์- NULL? takes one parameter;
- It returns #T if the parameter is the empty list; otherwise #F
- x ๊ฐ ๋น ๋ฆฌ์คํธ์ธ์ง ํ์ธ
(NULL? '(A B))returns#F(NULL? '())returns#T(NULL? 'A)returns#F; ์ฌ๋ณผ์ ๋ฆฌ์คํธ๋, ๋น ๋ฆฌ์คํธ๋ ์๋(NULL? '(()))yields#F; ์์๋ก ๋น ๋ฆฌ์คํธ๋ฅผ ๊ฐ์ง ๋ฆฌ์คํธ โ ๋น์ด์์ง ์์
Example Scheme Function: sort
(DEFINE (insert atm lst)
(COND
((NULL? lst) (CONS atm '()))
((< atm (CAR lst)) (CONS atm lst))
(ELSE (CONS (CAR lst) (insert atm (CDR lst))))))
(DEFINE (sort lst)
(if (NULL? lst)
'()
(insert (CAR lst) (sort (CDR lst)))))
(sort '(3 7 5 1 9)) ; returns (1 3 5 7 9)
(insert atm lst)
๋ชฉ์ : ์ซ์ ํ๋ atm์ ์ ๋ ฌ๋ ๋ฆฌ์คํธ lst์ ์๋ง์ ์์น์ ์ฝ์
์๋ ๋ฐฉ์:
๋ฆฌ์คํธ๊ฐ ๋น์์ผ๋ฉด โ ๋จ๋ ๋ฆฌ์คํธ๋ก ๋ง๋ค๊ธฐ
atm์ด ๋ฆฌ์คํธ์ ์ฒซ ์์๋ณด๋ค ์์ผ๋ฉด โ ์์ ๋ฃ๊ธฐ
์๋๋ฉด โ ๋ฆฌ์คํธ์ ๋๋จธ์ง์ ์ฌ๊ท์ ์ผ๋ก ์ฝ์
(sort lst)
๋ชฉ์ : ๋ฆฌ์คํธ lst๋ฅผ ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ ฌ
์๋ ๋ฐฉ์:
๋ฆฌ์คํธ๊ฐ ๋น์์ผ๋ฉด โ ๋น ๋ฆฌ์คํธ ๋ฐํ
์๋๋ฉด โ ์ฒซ ์์๋ ๋นผ์ sort๋ก ์ ๋ ฌํ ๋๋จธ์ง์ insertํจ์๋ก ์ฝ์
Example C Function: sort
// insert: ์ ๋ ฌ๋ ๋ฆฌ์คํธ์ value ์ฝ์
Node* insert(int value, Node* lst) {
if (lst == NULL || value < lst->value) {
Node* new_node = create_node(value);
new_node->next = lst;
return new_node;
} else {
lst->next = insert(value, lst->next);
return lst;
}
}
// sort: ์ฝ์
์ ๋ ฌ
Node* sort(Node* lst) {
if (lst == NULL) return NULL;
Node* sorted = sort(lst->next);
return insert(lst->value, sorted);
}
insert(int value, Node* lst)
๋ชฉ์ : ์ซ์ ํ๋ value์ ์ ๋ ฌ๋ ๋ฆฌ์คํธ lst์ ์๋ง์ ์์น์ ์ฝ์
์๋ ๋ฐฉ์:
๋ฆฌ์คํธ๊ฐ ๋น์๊ฑฐ๋, value๊ฐ ๋ฆฌ์คํธ์ ์ฒซ ์์๋ณด๋ค ์์ผ๋ฉด โ ์์ ๋ฃ๊ธฐ
์๋๋ฉด โ ๋ฆฌ์คํธ์ ๋๋จธ์ง์ ์ฌ๊ท์ ์ผ๋ก ์ฝ์
sort(Node* lst)
๋ชฉ์ : ๋ฆฌ์คํธ lst๋ฅผ ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ ฌ
์๋ ๋ฐฉ์:
๋ฆฌ์คํธ๊ฐ ๋น์์ผ๋ฉด โ ๋น ๋ฆฌ์คํธ ๋ฐํ
์๋๋ฉด โ ์ฒซ ์์๋ ๋นผ์ sort๋ก ์ ๋ ฌํ ๋๋จธ์ง์ insertํจ์๋ก ์ฝ์
Example Scheme Function: member
(DEFINE (member atm a_list)
(COND
((NULL? a_list) #F) ; ๋ฆฌ์คํธ๊ฐ ๋น์์ผ๋ฉด ์ฐพ์ ์ ์์
((EQ? atm (CAR a_list)) #T) ; ์ฒซ ์์๊ฐ ๊ฐ์ผ๋ฉด ์ฐพ์์
(ELSE (member atm (CDR a_list))))) ; ์๋๋ฉด ๋๋จธ์ง์์ ๊ณ์ ์ฐพ๊ธฐ
(member 'B '(A B C)) ; returns #T
(member 'B '(A C D E)) ; returns #F
// ๋ฆฌ์คํธ์ ํด๋น ๊ฐ์ด ์๋์ง ๊ฒ์ฌ (member ํจ์)
bool member(const char* atom, Node* list) {
if (list == NULL) return false;
if (strcmp(atom, list->value) == 0)
return true;
return member(atom, list->next);
}
Example Scheme Function: equalsimp
- equalsimp takes two simple lists as parameters; returns #T if the two simple lists are equal; #F otherwise
(DEFINE (equalsimp list1 list2)
(COND
((NULL? list1) (NULL? list2)) ; ๋ ๋ค ๋น ๋ฆฌ์คํธ๋ฉด ๊ฐ์
((NULL? list2) #F) ; list1๋ง ๋น์๊ณ list2๋ ์ ๋น์์ผ๋ฉด ๋ค๋ฆ
((EQ? (CAR list1) (CAR list2)) ; ์ฒซ ์์๊ฐ ๊ฐ์ผ๋ฉด
(equalsimp (CDR list1) (CDR list2))) ; ๋๋จธ์ง๋ฅผ ์ฌ๊ท์ ์ผ๋ก ๋น๊ต
(ELSE #F))) ; ์ฒซ ์์๊ฐ ๋ค๋ฅด๋ฉด ๋ค๋ฆ
- *Simple list: ๋ฆฌ์คํธ ์์ ๋ ๋ค๋ฅธ ๋ฆฌ์คํธ๊ฐ ์๋ ๊ตฌ์กฐ. ๋ชจ๋ ์์๊ฐ ์์(atom) ๋๋ ์ฌ๋ณผ(symbol) ๊ฐ์ ๋จ์ํ ๊ฐ
// equalsimp ํจ์: ๋ ๋ฆฌ์คํธ๊ฐ ๊ฐ์์ง ๋น๊ต
bool equalsimp(Node* list1, Node* list2) {
if (list1 == NULL && list2 == NULL)
return true;
if (list1 == NULL || list2 == NULL)
return false;
if (strcmp(list1->value, list2->value) != 0)
return false;
return equalsimp(list1->next, list2->next);
}
Example Scheme Function: equal
- equal takes two general lists as parameters;
- Complex than simple list case because sublist must be traced (๋ฆฌ์คํธ ์์ sublist๊ฐ ์์ด๋ ๋น๊ต ๊ฐ๋ฅ)
- Returns #T if the two lists are equal; #F otherwise (๋ ๋ฆฌ์คํธ๊ฐ ๋ชจ์๊ณผ ๊ฐ ๋ชจ๋ ๊ฐ์์ง๋ฅผ ํ๋จ)
(DEFINE (equal list1 list2)
(COND
((NOT (LIST? list1)) (EQ? list1 list2)) ; Handle the situation where either of the parameters is an atom instead of a list
((NOT (LIST? list2)) #F)
((NULL? list1) (NULL? list2)) ; Handle the situation where one or both lists are empty
((NULL? list2) #F)
((equal (CAR list1) (CAR list2)) ; ์ฒซ ์์ ๋น๊ต
(equal (CDR list1) (CDR list2))) ; ๋๋จธ์ง ๋น๊ต
(ELSE #F)))
- equal is equivalent to
EQUAL?(but slower thanEQ?andEQV?)
Example Scheme Function: append
- append takes two lists as parameters;
- Returns the first parameter list with the elements of the second parameter list appended at the end
(append '(A B) '(C D R))returns(A B C D R)(append '((A B) C) '(D (E F)))returns((A B) C D (E F))
(DEFINE (append list1 list2)
(COND
((NULL? list1) list2) ; list1์ด ๋น์์ผ๋ฉด, list2 ๊ทธ๋๋ก ๋ฐํ
(ELSE (CONS (CAR list1) ; list1์ ์ฒซ ์์๋ฅผ ์ ์งํ๊ณ
(append (CDR list1) list2))))) ; ๋๋จธ์ง(list1์ ๊ผฌ๋ฆฌ)์ list2๋ฅผ ์ฌ๊ท์ ์ผ๋ก ์ด์ด๋ถ์
Example Scheme Function: guess
- guess takes two lists as parameters;
- Yields a simple list that contains the common elements of its two parameter lists
- ๋ ๋ฆฌ์คํธ ๊ฐ์ ๊ณตํต ์์๋ฅผ ์ฐพ์๋ด๋ ํจ์
(DEFINE (guess list1 list2)
(COND
((NULL? list1) '()) ; list1์ด ๋น์์ผ๋ฉด ๊ณตํต ์์๋ ์์ผ๋ฏ๋ก ๋น ๋ฆฌ์คํธ ๋ฐํ
((member (CAR list1) list2) ; list1์ ์ฒซ ์์๊ฐ list2์ ํฌํจ๋๋ฉด
(CONS (CAR list1) (guess (CDR list1) list2))) ; ๊ทธ ์์๋ฅผ ๊ฒฐ๊ณผ์ ์ถ๊ฐํ๊ณ ๋๋จธ์ง ์ฌ๊ท ํธ์ถ
(ELSE (guess (CDR list1) list2)))) ; ํฌํจ๋์ง ์์ผ๋ฉด ๊ทธ๋ฅ ๋๋จธ์ง์์ ๊ณ์ ํ์
(guess '(A B C D) '(B D F)) ; โ (B D)
Example Scheme Function: adder
- adder takes lists as parameters;
- Yields sum of the lists (์ซ์๋ก๋ง ๊ตฌ์ฑ๋ ๋ฆฌ์คํธ์ ํฉ์ ๊ณ์ฐํ๋ ํจ์)
(DEFINE (adder a_list)
(COND
((NULL? a_list) 0) ; ๋ฆฌ์คํธ๊ฐ ๋น์์ผ๋ฉด ํฉ์ 0
(ELSE (+ (CAR a_list) (adder (CDR a_list)))))) ; ์ฒซ ์์์ ๋๋จธ์ง์ ํฉ์ ๋ํจ
(adder '(1 2 3)) returns 6
(adder '(1 (2) 3)) returns error
int adder(Node* list) {
if (list == NULL)
return 0;
return list->value + adder(list->next);
}
- Resolved! (์ค์ฒฉ ๋ฆฌ์คํธ(nested list)๊น์ง ๋ชจ๋ ์ํํด์ ์์ ์๋ ์ซ์๋ฅผ ์ ๋ถ ํฉ์ฐ)
(DEFINE (adder a_list)
(COND
((NULL? a_list) 0) ; ๋ฆฌ์คํธ๊ฐ ๋น์์ผ๋ฉด 0 ๋ฐํ
((LIST? (CAR lst)) ; ์ฒซ ์์๊ฐ ๋ฆฌ์คํธ์ด๋ฉด
(+ (adder (CAR lst)) (adder (CDR lst)))) ; ๊ทธ ๋ฆฌ์คํธ์ ๋๋จธ์ง๋ฅผ ์ฌ๊ท์ ์ผ๋ก ๋ํจ
(ELSE (+ (CAR a_list) (adder (CDR a_list)))))) ; ์ซ์๋ฉด ๊ทธ๋๋ก ๋ํ๊ณ ๋๋จธ์ง ์ฌ๊ท ํธ์ถ
int adder(Node* list) {
if (list == NULL) return 0;
Element e = list->value;
int head_sum = 0;
if (e.type == NUMBER) {
head_sum = e.number;
} else if (e.type == LIST) {
head_sum = adder(e.list); // ์ค์ฒฉ ๋ฆฌ์คํธ ์ฌ๊ท ํธ์ถ
}
return head_sum + adder(list->next);
}
Example Scheme Function: LET
- LET is actually shorthand for a LAMBDA expression applied to a parameter
- LET์ ์ด๋ฆ์ ๊ฐ์ ์์๋ก ๋ฐ์ธ๋ฉํ๊ณ , ๊ทธ ๊ฐ์ ํํ์ ์์์ ์ฌ์ฉํ๋ ๊ตฌ์กฐ
- ์ค์ ๋ก๋ LAMBDA + ์ฆ์ ํธ์ถ๋ก ๊ตฌํ๋ ๋ฌธ๋ฒ์ ํธ์(syntactic sugar)
(LET ((alpha 7)) (* 5 alpha)); โ 35- is the same as:
((LAMBDA (alpha) (* 5 alpha)) 7) - alpha๋ผ๋ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ (* 5 alpha)๋ฅผ ์ํ ์ธ์ 7์ด alpha์ ์ ๋ฌ๋จ
- LET creates a local scope in which names are temporarily bound to the values of expressions
- These names can then be used in the evaluation of another expression, but they cannot be rebound to new values in LET.
- LET ๋ด๋ถ์์ ๋ฐ์ธ๋ฉ๋ ์ด๋ฆ์ ๋ค์
SET!๋ฑ์ผ๋ก ๋ฐ๊ฟ ์ ์์ - ๋ณ์ ์ฌ์ ์๋ ๋ถ๊ฐ๋ฅ: ๋จ์ํ ๊ฐ ํ๋๋ฅผ ์ผ์์ ์ผ๋ก ํ ๋นํ ๋ฟ
LET Example
- ์ด์ฐจ๋ฐฉ์ ์์ ๊ทผ์ ๊ณต์์ ์ด์ฉํด ๋ ๊ทผ์ ๊ตฌํ๋ ํจ์
(DEFINE (quadratic_roots a b c)
(LET (
; ํ๋ณ์์ ์ ๊ณฑ๊ทผ์ 2a๋ก ๋๋ ๋ถ๋ถ
(root_part_over_2a
(/ (SQRT (- (* b b) (* 4 a c))) (* 2 a)))
(minus_b_over_2a (/ (- 0 b) (* 2 a))))
; ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌ์คํธ๋ก ๋ฐํ: ๋ ๊ทผ
(LIST (+ minus_b_over_2a root_part_over_2a)
(- minus_b_over_2a root_part_over_2a))))
Tail Recursion in Scheme
- Definition: A function is tail recursive if its recursive call is the last operation in the function โ ์ฆ, ์ฌ๊ท ํธ์ถ ๋ค์ ์๋ฌด ์ฐ์ฐ๋ ๋จ์ง ์์์ผ ํจ
- A tail recursive function can be automatically converted by a compiler to use iteration, making it faster
- ์ปดํ์ผ๋ฌ๊ฐ ์คํ ํ๋ ์์ ์ ์งํ์ง ์๊ณ , ๋ฐ๋ณต๋ฌธ์ฒ๋ผ ์ฒ๋ฆฌํ ์ ์์ โ ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น ์์, ์ฑ๋ฅ ํฅ์, ์คํ ์ค๋ฒํ๋ก์ฐ ๋ฐฉ์ง
- Scheme language definition requires that Scheme language systems convert all tail recursive functions to use iteration
- Scheme ์ปดํ์ผ๋ฌ ๋๋ ์ธํฐํ๋ฆฌํฐ๋ tail call์ ์๋์ผ๋ก ์ต์ ํํด์ผ ํจ
(DEFINE (member atm a_list)
(COND
((NULL? a_list) #F)
((EQ? atm (CAR a_list)) #T)
(ELSE (member atm (CDR a_list)))))
- Example of rewriting a function to make it tail recursive, using helper a function
; Original
(DEFINE (factorial n)
(IF (<= n 0)
1
(* n (factorial (- n 1)))))
; Tail recursive
(DEFINE (factorial n)
(DEFINE (facthelper n factpartial)
(IF (<= n 0)
factpartial
(facthelper (- n 1) (* n factpartial))))
(facthelper n 1))
Functional Form - Composition
- If h is the composition of f and g,
h(x) = f(g(x))(๋ ํจ์ f์ g๋ฅผ ํฉ์ณ์ ์๋ก์ด ํจ์ h๋ฅผ ๋ง๋๋ ๊ฒ)
(DEFINE (g x) (* 3 x)) ; g(x) = 3 * x
(DEFINE (f x) (+ 2 x)) ; f(x) = x + 2
(DEFINE (h x) (f (g x))) ; ํจ์ ํฉ์ฑ
(DEFINE (h x) (+ 2 (* 3 x))) ; (The composition) ; f(g(x)) ์ง์ ๊ณ์ฐ
- In Scheme, the functional composition function compose can be written:
- ํฉ์ฑ์ฉ ๊ณ ์ฐจ ํจ์ compose๋ฅผ ์ง์ ์ ์ํ ์๋ ์์
(DEFINE (compose f g)
(LAMBDA (x)
(f (g x))))
compose๋ ๋ ํจ์๋ฅผ ๋ฐ์์ ์๋ก์ด ํฉ์ฑ ํจ์๋ฅผ ๋ง๋ค์ด ๋ฐํ
(compose f g)๋ ์ํ์ ์ผ๋กf(g(x))์ ๊ฐ์((compose CAR CDR) '((a b) c d))yieldscโ CADRCDR โ
((a b) c d)์ ๊ผฌ๋ฆฌ:(c d)CAR โ
(c d)์ ์ฒซ ์์:c๊ฒฐ๊ณผ:
cโ ์ฆ, CADR((compose CDR CAR) '((a b) c d))yields(b)โ CDARCAR โ
((a b) c d)์ ์ฒซ ์์:(a b)CDR โ
(a b)์ ๊ผฌ๋ฆฌ:(b)๊ฒฐ๊ณผ:
(b)โ ์ฆ, CDAR(DEFINE (third a_list)((compose CAR (compose CDR CDR)) a_list))is equivalent to CADDR(compose CDR CDR)โ CDDRcompose CAR ...โCAR(CDDR(x))โ ์ฆ, CADDR
Functional Form โ Apply-to-All
- Apply to All - one form in Scheme is map
- Applies the given function to all elements of the given list
- ๋ฆฌ์คํธ์ ๋ชจ๋ ์์์ ์ด๋ค ํจ์๋ฅผ ์ ์ฉํด์ ์๋ก์ด ๋ฆฌ์คํธ๋ฅผ ๋ง๋๋ ํจ์
(DEFINE (map fun a_list)
(COND ((NULL? a_list) '()) ; ๋ฆฌ์คํธ๊ฐ ๋น์์ผ๋ฉด ๋น ๋ฆฌ์คํธ ๋ฐํ
(ELSE (CONS (fun (CAR a_list)) ; ํ์ฌ ์์์ ํจ์ ์ ์ฉ
(map fun (CDR a_list)))))) ; ๋๋จธ์ง ๋ฆฌ์คํธ์ ์ฌ๊ท์ ์ผ๋ก map
(map (LAMBDA (num) (* num num num)) '(3 4 2 6))yields(27 64 8 216)(cons 27 (cons 64 (cons 8 (cons 216 '()))))โ(27 64 8 216)
FOLD โ ๋์ ๊ณ์ฐ
(DEFINE (FOLD F BASE A_LIST)
(COND
((NULL? A_LIST) BASE) ; ๋ฆฌ์คํธ ๋ โ ๋์ ๊ฐ ๋ฐํ
(ELSE (F (CAR A_LIST) (FOLD F BASE (CDR A_LIST)))))) ; ์ฌ๊ท์ ์ผ๋ก ๋์ ๊ณ์ฐ
(FOLD + 0 '(1 2 3 4)) ; โ 10
(FOLD * 1 '(2 3 4)) ; โ 24
FILTER โ ์กฐ๊ฑด์ ๋ง๋ ๊ฐ๋ง ๊ฑธ๋ฌ๋ด๋ ํจ์
(DEFINE (FILTER PRED A_LIST)
(COND
((NULL? A_LIST) '()) ; ๋ฆฌ์คํธ๊ฐ ๋น์์ผ๋ฉด ์ข
๋ฃ
((PRED (CAR A_LIST))
(CONS (CAR A_LIST) (FILTER PRED (CDR A_LIST)))) ; ํ์ฌ ์์๊ฐ ์กฐ๊ฑด ๋ง์กฑ โ ํฌํจ + ๋๋จธ์ง ์ฌ๊ท
(ELSE (FILTER PRED (CDR A_LIST))))) ; ์กฐ๊ฑด ๋ถ๋ง์กฑ โ ๊ฑด๋๋ฐ๊ธฐ
(FILTER EVEN? '(1 2 3 4)) ; โ (2 4)
Functions That Build Code
It is possible in Scheme to define a function that builds Scheme code and requests its interpretation
- Scheme์ โ์ฝ๋๋ฅผ ๋ฐ์ดํฐ์ฒ๋ผโ ๋ค๋ฃฐ ์ ์๋ ์ธ์ด
- ๊ทธ๋์ ์ฝ๋๋ฅผ ์์ฑํ๋ ํจ์๋ฅผ ๋ง๋ค๊ณ , ๊ทธ ์ฝ๋๋ฅผ ํด์ํด์ ์คํํ ์๋ ์์.
- Scheme์ด ๊ฐ์ง ๋ฉํํ๋ก๊ทธ๋๋ฐ ๋ฅ๋ ฅ ์ค ํ๋
- This is possible because the interpreter is a user-available function, EVAL
- Scheme์์๋ ์ฝ๋ ๊ตฌ์กฐ๊ฐ ๋ฆฌ์คํธ(S-expression) ํํ
- ํ๋ก๊ทธ๋จ ์์์ ์ฝ๋๋ฅผ ์กฐ๋ฆฝํ๊ณ , EVAL์ ํตํด ๊ทธ๊ฑธ ์ค์ ๋ก ์คํํ ์ ์์
(DEFINE (make-def name val)
(LIST 'DEFINE name val))
- ํจ์
make-def๋ ์ค์ ๋ก ์ ์๋ฌธ(DEFINE x 42)๋ฅผ "๋ฐ์ดํฐ"๋ก ๋ง๋ ๋ค์, EVAL์ ํตํด ์คํ์์ผ โ ์ค์ ๋ก ๋ณ์๋ฅผ ์ ์ํจ (make-def 'x 42); โ'(DEFINE x 42)(EVAL (make-def 'x 42) (interaction-environment))x; โ 42
Adding a List of Numbers
The parameter is a list of numbers to be added;
- Cannot apply
+directly on the list, because+can take only atomic parameters - Write a function that repeatedly adds the CAR of the list to the sum of its CDR, using recursion
(DEFINE (adder a_list)
(COND
((NULL? a_list) 0)
(ELSE (+ (CAR a_list) (adder (CDR a_list))))))
- adder inserts a
+operator and evaluates the resulting list - Use CONS to insert the atom
+into the list of numbers. - Be sure that
+is quoted to prevent evaluation - Submit the new list to EVAL for evaluation
(DEFINE (adder a_list)
(COND
((NULL? a_list) 0)
(ELSE (EVAL (CONS '+ a_list)))))
- ๋ฆฌ์คํธ์ ์ซ์๋ค์ ๋ค ๋ํด์ผ ํ๋๋ฐ,
+์ฐ์ฐ์๋ฅผ ๋ฆฌ์คํธ ์์ ๋ถ์ฌ์ ํ๋์ Scheme ์ฝ๋๋ก ๋ง๋ ๋ค, ๊ทธ๊ฑธ EVAL๋ก ์คํํ๋ ๋ฐฉ์

