SlideShare a Scribd company logo
Haskell
Study
4. syntax in functions
Pattern matching
패턴 매칭은 함수를 만들 때 사용할 수 있는 굉장히 강력한 구문입니다. 패턴 매칭은 어떤 데이터가
가져야 할 패턴을 명시하고, 데이터가 있을 때 그 데이터가 해당 패턴에 맞춰 분해될 수 있는 지
확인하는 과정을 거칩니다. Haskell에서 함수는 데이터의 패턴에 따라 서로 다른 여러 개의 본체를
가질 수 있습니다.
f :: (Integral a, Num b) => a -> b
f 0 = 0
f 1 = 1
f n = f (n-1) + f (n-2)
Prelude> f 10
55
위와 같이 패턴 매칭을 이용해 피보나치 함수를 굉장히 쉽고 직관적으로 구현할 수 있습니다.
Pattern matching
패턴 매칭은 위에서부터 차례대로 내려오며 검사합니다. 즉, 패턴에 따른 함수 구현의 순서가 서로
다르면 결과 역시 달라집니다. 아래 두 함수를 봅시다.
f :: (Integral a) => a -> String
f n = "must run this function!"
f 0 = "it’s 0"
f2 :: (Integral a) => a -> String
f2 0 = "it’s 0"
f2 n = "must run this function!"
이 두 함수는 패턴에 따른 함수 선언의 순서만 바꿨을 뿐이지만 결과가 전혀 달라집니다.
Pattern matching
*Main> f 0
“must run this function!”
*Main> f 1
“must run this function!”
*Main> f2 0
“it’s 0”
*Main> f2 1
“must run this function!”
위와 같이 함수 f의 경우 f n에 대한 정의가 먼저 이루어지면서, 모든 인자에 대해 ‘n’이라는 패턴이
성립하므로 아래의 f 0 패턴까지 가지 못하고 함수가 실행됩니다. 그래서 패턴 매칭을 할 때는 명확한(
특수한) 패턴을 앞에 두고, 보다 일반적인 패턴을 뒤에 두게끔 작성하시는 것이 좋습니다.
Pattern matching
패턴 매칭은 실패할 수도 있습니다. 이 경우 예외가 발생합니다.
foo :: Int -> Int
foo 0 = 0
foo 1 = 1
foo 2 = 2
*Main> f 0
0
*Main> f 4
*** Exception: test.hs:(2,1)-(4,7): Non-exhaustive patterns in
function f
패턴 매칭을 쓸 때는 모든 종류의 패턴이 매칭될 수 있게끔 신경써서 코딩해야 합니다.
Pattern matching
튜플에 대한 패턴 매칭도 가능합니다. 두 개의 벡터 값을 더하는 함수를 생각해보죠.
addVector :: (Num a) => (a,a) -> (a,a) -> (a,a)
addVector a b = (fst a + fst b, snd a + snd b)
물론 위 함수도 잘 동작하지만, 아래 코드가 좀 더 깔끔합니다.
addVector :: (Num a) => (a,a) -> (a,a) -> (a,a)
addVector (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
이런 패턴 매칭을 이용해서 원소가 3개인 페어(트리플)에서 특정 한 원소를 꺼내오는 함수를 작성할
수 있습니다.
Pattern matching
first :: (a,b,c) -> a
first (x, _, _) = x
second :: (a,b,c) -> b
second (_, y, _) = y
third :: (a,b,c) -> c
third (_, _, z) = z
패턴 매칭에서 해당 위치에 오는 값에 아무런 관심이 없는 경우(뭐가 와도 상관없는 경우)에는 _
기호를 이용합니다.
Pattern matching
패턴 매칭은 list comprehension에서도 이용할 수 있습니다.
pairToNum :: (Num a) => [(a,a)] -> [a]
pairToNum xs = [a+b | (a,b) <- xs]
*Main> pairToNum [(3,4), (1,2), (5,7), (6,3)]
[7,3,12,9]
Pattern matching
튜플과 비슷하게 리스트에서도 패턴 매칭을 이용할 수 있습니다. 텅빈 리스트([]), cons 연산자(:)
등을 이용해서 패턴에서 해당 리스트가 가져야 할 형태를 나타낼 수 있습니다. 패턴 매칭을 이용해서
한 번 head 함수를 구현해봅시다.
head' :: [a] -> a
head' [] = error "Can't call head on empty list."
head' (x:_) = x
error 함수는 런타임 에러를 발생시키는 함수입니다. 잘못된 케이스의 함수 호출에 대해 간략한
정보를 남긴 후 프로그램을 죽일 때 사용합니다.
Pattern matching
다른 몇 가지 예시도 한 번 살펴봅시다.
length' :: (Num b) => [a] -> b
length' [] = 0
length' (_:xs) = 1 + length' xs
sum' :: (Num a) => [a] -> a
sum' [] = 0
sum' (x:xs) = x + sum' xs
Pattern matching
패턴 및 해당 데이터 전체가 모두 필요한 경우 @를 이용할 수 있습니다.
headFirst :: (Show a) => [a] -> String
headFirst [] = "empty string"
headFirst all@(x:_) = show all ++ "'s first element is " ++ show x
*Main> headFirst [1,2,3,4]
"[1,2,3,4]'s first element is 1"
*Main> headFirst "abcd"
""abcd"'s first element is 'a'"
연습 문제
•	yesNo
Bool 값 하나를 인자로 받아 그 값이 True면 "Yes", False면 "No"를 리턴하는 함수를 만들어 봅시다.
예를 들어 yesNo (True || False) 는 "Yes"를 리턴해야 합니다.
•	trueman
Bool 값 리스트를 인자로 받아 True인 원소의 개수를 리턴하는 함수를 만들어 봅시다. 예를 들어
trueman [True,True,False,False,True]는 3을 리턴해야 합니다.
•	listToPairs
list를 인자로 받아 각 원소를 두 개씩 순서대로 짝 지은 페어의 리스트를 리턴하는 함수를 만들어
봅시다. 원소 개수가 홀수 개인 경우 마지막 원소는 버립니다. 예를 들어 listToPairs [1,2,3,4,5] 는
[(1,2), (3,4)]를 리턴해야합니다.
Guard
패턴 매칭이 데이터가 특정 패턴을 만족하는 지를 판단하는 방법인 반면 가드는 데이터가 특정 조건을
만족하는 지를 판단하는 방법입니다. 여러 개의 if ~ else if가 나열되어 있는 구조와 비슷한 형태라고
생각하면 됩니다. 우선 예제를 봅시다.
bmiTell :: (Floating a) => a -> String
bmiTell bmi
	 | bmi <= 18.5 = "You are underweight."
	 | bmi <= 25.0 = "you are normal."
	 | bmi <= 30.0 = "you are fat."
	 | otherwise = "you are very fat."
가드는 인자 다음에 파이프(|)와 논리 표현식을 이용해 표현합니다. 위에서부터 순서대로 인자가
조건을 만족하는지 확인한 다음에 만족한다면 거기에 해당하는 코드를 실행합니다.
Guard
가드는 보통 앞의 예제와 같이 여러 줄에 가드의 각 조건과 거기에 해당하는 코드를 나열합니다.
조건을 여러 줄에 나눠 쓸 때는 인덴트(indent)에 조심하셔야 합니다. 각 파이프의 위치가 서로
인덴트가 다르다면 컴파일 에러가 발생합니다.
보통 가드의 맨 마지막은 otherwise입니다. otherwise는 단순히 True로 정의되어 있으며, 다른
가드가 처리하지 못한 조건을 처리하기 위해 존재합니다.
패턴과 가드를 같이 쓸 경우, 가드에서 만족하는 조건이 없을 경우 단순히 다음 패턴으로 넘어갑니다.
다음 패턴이 존재하지 않는다면 마찬가지로 예외가 발생합니다. 그리고 가드를 쓸 때 한 줄에 모든
코드를 다 써도 상관없지만, 가독성이 떨어지기 때문에 별로 추천할만한 방식은 아닌 것 같네요.
max' :: (Ord a) => a -> a -> a
max' a b | a > b = a | otherwise = b
where
where 절은 해당 함수 내부에서 반복적으로 쓰이는 여러 표현식 등을 위해 사용됩니다. 앞의 bmiTell
함수를 where를 이용해 수정해보겠습니다.
bmiTell :: (Floating a) => a -> a -> String
bmiTell weight height
	 | bmi <= 18.5 = "You are underweight."
	 | bmi <= 25.0 = "You are normal."
	 | bmi <= 30.0 = "You are fat."
	 | otherwise = "You are very fat."
	 where bmi = weight / height ^ 2
키와 몸무게를 인자로 받아 bmi지수를 계산해서 판단하게끔 했고, 이 때 bmi 계산 공식은
반복적으로 쓰이기 때문에 where 절을 이용했습니다.
where
where는 코드의 가독성을 높여줄 뿐만 아니라 같은 계산식은 한 번만 계산해도 되게 만들어줌으로써
실행 속도의 향상까지 가져옵니다. where 절 내부의 내용은 해당 함수 내에서만 사용 가능합니다.
또 where 절에서도 패턴 매칭을 이용할 수 있습니다.
bmiTell :: (Floating a) => a -> a -> String
bmiTell weight height
	 | bmi <= skinny = “You are underweight.”
	 | bmi <= normal = “You are normal.”
	 | bmi <= fat = “You are fat.”
	 | otherwise = “You are very fat.”
	 where bmi = weight / height ^ 2
	 (skinny, normal, pat) = (18.5, 25.0, 30.0)
where
where 절 내부에서도 함수를 선언할 수 있으며, where 절 내부에 where절을 중첩해서 쓸 수도
있고, 함수를 만드는 데 필요한 문법들(패턴 매칭, 가드 등)도 모두 사용 가능합니다.
calcFibos :: (Integral a) => [a] -> a
calcFibos xs = [fibo x | x <- xs]
	 where fibo 0 = 0
	 fibo 1 = 1
	 fibo n = fibo (n-1) + fibo (n-2)
let in
let in 표현식은 where 절과 비슷한 역할을 합니다. let (bindings) in (expression)의 형태를 하고
있으며, where이 뒤에 binding이 오는 반면 let은 binding이 앞에 온다는 차이점이 있습니다.
cylinder :: (Num a) => a -> a -> a
cylinder r h =
	 let sideArea = 2 * pi * r * h
	 topArea = pi * r^2
	 in sideArea + 2 * topArea
let in 표현식은 let 절에서 바인딩한 값을 in 뒤에서 사용할 수 있습니다. 또 where절이 구문적인
구조인 반면 let in 표현식은 if문처럼 코드 상의 어디서든지 등장할 수 있습니다. 즉, let in 표현식은
그 자체로 평가되며 결과 값이 존재해야만 합니다.
let in
한 줄에 여러 개의 바인딩을 하고 싶다면 세미콜론(;)을 이용합니다.
Prelude> let a = 5 in a * a * a
125
Prelude> let squre x = x * x in (squre 5, squre 6)
(25, 36)
Prelude> let a = 100; b = 200; c = 300; in a + b + c
600
list comprehension에서도 let을 사용할 수 있습니다. 이 때 let은 바인딩의 역할만 합니다.
Prelude> [f x|x<-[0..10],let f 0=0;f 1=1;f n=f (n-1)+f (n-2)]
[0,1,1,2,3,5,8,13,21,34,55]
case expression
case 표현식은 명령형 언어의 switch - case 구문과 비슷한 개념이나, 훨씬 강력한 기능을 갖고
있습니다. case 표현식 역시 표현식이기 때문에 평가되는 값이고, 코드의 중간에 사용할 수 있습니다.
구문은 아래와 같은 구조를 갖고 있습니다.
case expression of pattern -> result
pattern -> result
pattern -> result
...
함수 인자의 패턴 매칭과 굉장히 유사합니다. 특정 표현식의 패턴에 따른 결과 값을 case 표현식을
통해 나타낼 수 있습니다. 다만 함수에서의 패턴 매칭과는 다르게 case 표현식은 표현식이기 때문에
어디에서든지 사용가능합니다.
case expression
head’ :: [a] -> a
head’ xs = case xs of [] -> error "Can’t call head on empty list."
(x:_) -> x
descList :: [a] -> String
descList xs = "this List is " ++ case xs of [] -> "Empty List"
[x]-> "Singleton List"
xs -> "Long List"
연습 문제
•	maximum
어떤 리스트가 주어져 있을 때, 리스트의 원소중 가장 큰 원소를 리턴하는 함수를 구현해 봅시다. 빈
리스트의 경우 error 함수를 사용해서 런타임 에러를 일으키게끔 만들어 보세요.
•	take
숫자와 리스트가 주어졌을 때, 리스트에서 처음부터 해당 숫자만큼의 원소를 잘라서 리턴하는 함수를
만들어 봅시다. 단, 숫자가 0이하인 경우 빈 리스트([])를 리턴해야 합니다.
•	zip
두 개의 리스트가 주어졌을 때 두 리스트의 원소 각각을 튜플로 짝지은 리스트를 리턴하는 함수를
만들어 봅시다.
위 함수는 모두 표준에 존재하는 함수입니다. 이름을 조금 다르게 작성하셔야 합니다.
연습 문제
•	quickSort (* hard)
어떤 리스트가 주어져 있을 때, 그 리스트를 quickSort를 이용해 정렬하는 함수를 구현해봅시다.
처음에는 풀기 상당히 어려운 문제니 천천히 시간을 들여서 고민해봅시다.

More Related Content

PDF
Haskell study 3
PDF
Haskell study 5
PDF
Haskell study 2
PDF
Haskell study 6
PDF
Haskell study 1
PDF
Haskell study 8
PDF
Haskell study 9
PDF
Haskell study 13
Haskell study 3
Haskell study 5
Haskell study 2
Haskell study 6
Haskell study 1
Haskell study 8
Haskell study 9
Haskell study 13

What's hot (20)

PDF
Haskell study 12
PDF
Haskell study 14
PDF
Monad Laws Must be Checked
PPTX
Optimizing queries MySQL
PDF
The Power Of Composition (DotNext 2019)
PPTX
Python-List.pptx
PDF
Left and Right Folds - Comparison of a mathematical definition and a programm...
PPTX
Algoritmos de busqueda
PPTX
Método de Búsqueda Hash
PDF
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
PPT
Normalizacion
PDF
Interfaces .net
PDF
What is Python Lambda Function? Python Tutorial | Edureka
PDF
JAVA ORIENTADO A OBJETOS - HERENCIA
PDF
Node.js middleware: Never again!
PDF
Acerca de los algoritmos de mezcla en cajeros automáticos
PPT
Polymorphism in c++ ppt (Powerpoint) | Polymorphism in c++ with example ppt |...
PDF
Java ArrayList Tutorial | Edureka
PPTX
C# Types of classes
PDF
Four Languages From Forty Years Ago (NewCrafts 2019)
Haskell study 12
Haskell study 14
Monad Laws Must be Checked
Optimizing queries MySQL
The Power Of Composition (DotNext 2019)
Python-List.pptx
Left and Right Folds - Comparison of a mathematical definition and a programm...
Algoritmos de busqueda
Método de Búsqueda Hash
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Normalizacion
Interfaces .net
What is Python Lambda Function? Python Tutorial | Edureka
JAVA ORIENTADO A OBJETOS - HERENCIA
Node.js middleware: Never again!
Acerca de los algoritmos de mezcla en cajeros automáticos
Polymorphism in c++ ppt (Powerpoint) | Polymorphism in c++ with example ppt |...
Java ArrayList Tutorial | Edureka
C# Types of classes
Four Languages From Forty Years Ago (NewCrafts 2019)
Ad

Viewers also liked (20)

PDF
Haskell study 0
PPT
[2010 ChangeON] 세션 3 - 이미나
PDF
Marketer's writing 송세진 creative planner
PPTX
제3과 문법 단위
PPTX
[논문쓰는법]정치적으로 올바른 단어선택
PPTX
문서력 향상을 위한 실전 방법론
PPTX
명확한 끝 그림"은 몰입의 요약
PPTX
GPG 3.8 퍼지 논리
PDF
(07.03) 기획력완전정복4회_프레젠테이션, 설득의비법 (김용석)
PPT
07 프로젝트 이슈분석
PDF
E3 이야기의 구소
PPT
20110306_은혜를체험한사람들
PPTX
회사.. 언제 그만둘까?
PDF
KTH_Detail day_안드로메다에서 온 디자이너이야기_2차(1)_디자인프로세스,협업_한재기
PPTX
저드론인데요배달왔어요
PDF
프레젠테이션 그리고 디자인
PPTX
메세지의 기술
PDF
E4 단순화
PPTX
모듈ⅱ. 논리적 사고방법 실습
PPTX
성공하는 사람들이 퇴근 10분 전 꼭 챙기는 13가지 ppt
Haskell study 0
[2010 ChangeON] 세션 3 - 이미나
Marketer's writing 송세진 creative planner
제3과 문법 단위
[논문쓰는법]정치적으로 올바른 단어선택
문서력 향상을 위한 실전 방법론
명확한 끝 그림"은 몰입의 요약
GPG 3.8 퍼지 논리
(07.03) 기획력완전정복4회_프레젠테이션, 설득의비법 (김용석)
07 프로젝트 이슈분석
E3 이야기의 구소
20110306_은혜를체험한사람들
회사.. 언제 그만둘까?
KTH_Detail day_안드로메다에서 온 디자이너이야기_2차(1)_디자인프로세스,협업_한재기
저드론인데요배달왔어요
프레젠테이션 그리고 디자인
메세지의 기술
E4 단순화
모듈ⅱ. 논리적 사고방법 실습
성공하는 사람들이 퇴근 10분 전 꼭 챙기는 13가지 ppt
Ad

Similar to Haskell study 4 (20)

PDF
[SICP] 4.4 Logic Programming : 논리로 프로그램 짜기
PPTX
하스켈 프로그래밍 입문 2
PPTX
하스켈 프로그래밍 입문
PDF
Haskell study 10
PPTX
Sicp 2.2 계층 구조 데이터와 닫힘 성질
PDF
SHAKE - 경기 남부 4개대학 연합 프로그래밍 경시대회 본선문제
PDF
R 기초 : R Basics
PPT
Swift basic operators-controlflow
DOCX
이산치수학 Project4
PPT
Python3 brief summary
PPTX
R 기본-데이타형 소개
DOCX
이산치수학 Project2
PPTX
하스켈로 알고리즘 문제 풀기
PPTX
7장매크로
PPTX
하스켈 성능 튜닝
PDF
제3장 계산방법에대한 파이썬학습진행방법. 계산을 통해 python programing
PPTX
함수형 사고 - Functional thinking
PDF
Pure Function and Honest Design
PDF
2019 홍익대학교 프로그래밍 경진대회 풀이 슬라이드 (Open Contest용)
PDF
[이산수학]4 관계, 함수 및 행렬
[SICP] 4.4 Logic Programming : 논리로 프로그램 짜기
하스켈 프로그래밍 입문 2
하스켈 프로그래밍 입문
Haskell study 10
Sicp 2.2 계층 구조 데이터와 닫힘 성질
SHAKE - 경기 남부 4개대학 연합 프로그래밍 경시대회 본선문제
R 기초 : R Basics
Swift basic operators-controlflow
이산치수학 Project4
Python3 brief summary
R 기본-데이타형 소개
이산치수학 Project2
하스켈로 알고리즘 문제 풀기
7장매크로
하스켈 성능 튜닝
제3장 계산방법에대한 파이썬학습진행방법. 계산을 통해 python programing
함수형 사고 - Functional thinking
Pure Function and Honest Design
2019 홍익대학교 프로그래밍 경진대회 풀이 슬라이드 (Open Contest용)
[이산수학]4 관계, 함수 및 행렬

More from Nam Hyeonuk (16)

PPTX
Next 게임 실전 프로젝트 슬라이드
PDF
Haskell study 15
PDF
Haskell study 11
PDF
Haskell study 7
PDF
Multi thread
PDF
Memory & object pooling
PDF
Database
PDF
Exception&log
PDF
Iocp advanced
PDF
Iocp 기본 구조 이해
PDF
Tcp ip & io model
PDF
Effective c++ chapter 1,2 요약
PDF
구문과 의미론(정적 의미론까지)
PDF
Gpg 1.1
PDF
Stl vector, list, map
PDF
Age Of Empires II : Age Of Kings Postmotem
Next 게임 실전 프로젝트 슬라이드
Haskell study 15
Haskell study 11
Haskell study 7
Multi thread
Memory & object pooling
Database
Exception&log
Iocp advanced
Iocp 기본 구조 이해
Tcp ip & io model
Effective c++ chapter 1,2 요약
구문과 의미론(정적 의미론까지)
Gpg 1.1
Stl vector, list, map
Age Of Empires II : Age Of Kings Postmotem

Haskell study 4

  • 2. Pattern matching 패턴 매칭은 함수를 만들 때 사용할 수 있는 굉장히 강력한 구문입니다. 패턴 매칭은 어떤 데이터가 가져야 할 패턴을 명시하고, 데이터가 있을 때 그 데이터가 해당 패턴에 맞춰 분해될 수 있는 지 확인하는 과정을 거칩니다. Haskell에서 함수는 데이터의 패턴에 따라 서로 다른 여러 개의 본체를 가질 수 있습니다. f :: (Integral a, Num b) => a -> b f 0 = 0 f 1 = 1 f n = f (n-1) + f (n-2) Prelude> f 10 55 위와 같이 패턴 매칭을 이용해 피보나치 함수를 굉장히 쉽고 직관적으로 구현할 수 있습니다.
  • 3. Pattern matching 패턴 매칭은 위에서부터 차례대로 내려오며 검사합니다. 즉, 패턴에 따른 함수 구현의 순서가 서로 다르면 결과 역시 달라집니다. 아래 두 함수를 봅시다. f :: (Integral a) => a -> String f n = "must run this function!" f 0 = "it’s 0" f2 :: (Integral a) => a -> String f2 0 = "it’s 0" f2 n = "must run this function!" 이 두 함수는 패턴에 따른 함수 선언의 순서만 바꿨을 뿐이지만 결과가 전혀 달라집니다.
  • 4. Pattern matching *Main> f 0 “must run this function!” *Main> f 1 “must run this function!” *Main> f2 0 “it’s 0” *Main> f2 1 “must run this function!” 위와 같이 함수 f의 경우 f n에 대한 정의가 먼저 이루어지면서, 모든 인자에 대해 ‘n’이라는 패턴이 성립하므로 아래의 f 0 패턴까지 가지 못하고 함수가 실행됩니다. 그래서 패턴 매칭을 할 때는 명확한( 특수한) 패턴을 앞에 두고, 보다 일반적인 패턴을 뒤에 두게끔 작성하시는 것이 좋습니다.
  • 5. Pattern matching 패턴 매칭은 실패할 수도 있습니다. 이 경우 예외가 발생합니다. foo :: Int -> Int foo 0 = 0 foo 1 = 1 foo 2 = 2 *Main> f 0 0 *Main> f 4 *** Exception: test.hs:(2,1)-(4,7): Non-exhaustive patterns in function f 패턴 매칭을 쓸 때는 모든 종류의 패턴이 매칭될 수 있게끔 신경써서 코딩해야 합니다.
  • 6. Pattern matching 튜플에 대한 패턴 매칭도 가능합니다. 두 개의 벡터 값을 더하는 함수를 생각해보죠. addVector :: (Num a) => (a,a) -> (a,a) -> (a,a) addVector a b = (fst a + fst b, snd a + snd b) 물론 위 함수도 잘 동작하지만, 아래 코드가 좀 더 깔끔합니다. addVector :: (Num a) => (a,a) -> (a,a) -> (a,a) addVector (x1, y1) (x2, y2) = (x1 + x2, y1 + y2) 이런 패턴 매칭을 이용해서 원소가 3개인 페어(트리플)에서 특정 한 원소를 꺼내오는 함수를 작성할 수 있습니다.
  • 7. Pattern matching first :: (a,b,c) -> a first (x, _, _) = x second :: (a,b,c) -> b second (_, y, _) = y third :: (a,b,c) -> c third (_, _, z) = z 패턴 매칭에서 해당 위치에 오는 값에 아무런 관심이 없는 경우(뭐가 와도 상관없는 경우)에는 _ 기호를 이용합니다.
  • 8. Pattern matching 패턴 매칭은 list comprehension에서도 이용할 수 있습니다. pairToNum :: (Num a) => [(a,a)] -> [a] pairToNum xs = [a+b | (a,b) <- xs] *Main> pairToNum [(3,4), (1,2), (5,7), (6,3)] [7,3,12,9]
  • 9. Pattern matching 튜플과 비슷하게 리스트에서도 패턴 매칭을 이용할 수 있습니다. 텅빈 리스트([]), cons 연산자(:) 등을 이용해서 패턴에서 해당 리스트가 가져야 할 형태를 나타낼 수 있습니다. 패턴 매칭을 이용해서 한 번 head 함수를 구현해봅시다. head' :: [a] -> a head' [] = error "Can't call head on empty list." head' (x:_) = x error 함수는 런타임 에러를 발생시키는 함수입니다. 잘못된 케이스의 함수 호출에 대해 간략한 정보를 남긴 후 프로그램을 죽일 때 사용합니다.
  • 10. Pattern matching 다른 몇 가지 예시도 한 번 살펴봅시다. length' :: (Num b) => [a] -> b length' [] = 0 length' (_:xs) = 1 + length' xs sum' :: (Num a) => [a] -> a sum' [] = 0 sum' (x:xs) = x + sum' xs
  • 11. Pattern matching 패턴 및 해당 데이터 전체가 모두 필요한 경우 @를 이용할 수 있습니다. headFirst :: (Show a) => [a] -> String headFirst [] = "empty string" headFirst all@(x:_) = show all ++ "'s first element is " ++ show x *Main> headFirst [1,2,3,4] "[1,2,3,4]'s first element is 1" *Main> headFirst "abcd" ""abcd"'s first element is 'a'"
  • 12. 연습 문제 • yesNo Bool 값 하나를 인자로 받아 그 값이 True면 "Yes", False면 "No"를 리턴하는 함수를 만들어 봅시다. 예를 들어 yesNo (True || False) 는 "Yes"를 리턴해야 합니다. • trueman Bool 값 리스트를 인자로 받아 True인 원소의 개수를 리턴하는 함수를 만들어 봅시다. 예를 들어 trueman [True,True,False,False,True]는 3을 리턴해야 합니다. • listToPairs list를 인자로 받아 각 원소를 두 개씩 순서대로 짝 지은 페어의 리스트를 리턴하는 함수를 만들어 봅시다. 원소 개수가 홀수 개인 경우 마지막 원소는 버립니다. 예를 들어 listToPairs [1,2,3,4,5] 는 [(1,2), (3,4)]를 리턴해야합니다.
  • 13. Guard 패턴 매칭이 데이터가 특정 패턴을 만족하는 지를 판단하는 방법인 반면 가드는 데이터가 특정 조건을 만족하는 지를 판단하는 방법입니다. 여러 개의 if ~ else if가 나열되어 있는 구조와 비슷한 형태라고 생각하면 됩니다. 우선 예제를 봅시다. bmiTell :: (Floating a) => a -> String bmiTell bmi | bmi <= 18.5 = "You are underweight." | bmi <= 25.0 = "you are normal." | bmi <= 30.0 = "you are fat." | otherwise = "you are very fat." 가드는 인자 다음에 파이프(|)와 논리 표현식을 이용해 표현합니다. 위에서부터 순서대로 인자가 조건을 만족하는지 확인한 다음에 만족한다면 거기에 해당하는 코드를 실행합니다.
  • 14. Guard 가드는 보통 앞의 예제와 같이 여러 줄에 가드의 각 조건과 거기에 해당하는 코드를 나열합니다. 조건을 여러 줄에 나눠 쓸 때는 인덴트(indent)에 조심하셔야 합니다. 각 파이프의 위치가 서로 인덴트가 다르다면 컴파일 에러가 발생합니다. 보통 가드의 맨 마지막은 otherwise입니다. otherwise는 단순히 True로 정의되어 있으며, 다른 가드가 처리하지 못한 조건을 처리하기 위해 존재합니다. 패턴과 가드를 같이 쓸 경우, 가드에서 만족하는 조건이 없을 경우 단순히 다음 패턴으로 넘어갑니다. 다음 패턴이 존재하지 않는다면 마찬가지로 예외가 발생합니다. 그리고 가드를 쓸 때 한 줄에 모든 코드를 다 써도 상관없지만, 가독성이 떨어지기 때문에 별로 추천할만한 방식은 아닌 것 같네요. max' :: (Ord a) => a -> a -> a max' a b | a > b = a | otherwise = b
  • 15. where where 절은 해당 함수 내부에서 반복적으로 쓰이는 여러 표현식 등을 위해 사용됩니다. 앞의 bmiTell 함수를 where를 이용해 수정해보겠습니다. bmiTell :: (Floating a) => a -> a -> String bmiTell weight height | bmi <= 18.5 = "You are underweight." | bmi <= 25.0 = "You are normal." | bmi <= 30.0 = "You are fat." | otherwise = "You are very fat." where bmi = weight / height ^ 2 키와 몸무게를 인자로 받아 bmi지수를 계산해서 판단하게끔 했고, 이 때 bmi 계산 공식은 반복적으로 쓰이기 때문에 where 절을 이용했습니다.
  • 16. where where는 코드의 가독성을 높여줄 뿐만 아니라 같은 계산식은 한 번만 계산해도 되게 만들어줌으로써 실행 속도의 향상까지 가져옵니다. where 절 내부의 내용은 해당 함수 내에서만 사용 가능합니다. 또 where 절에서도 패턴 매칭을 이용할 수 있습니다. bmiTell :: (Floating a) => a -> a -> String bmiTell weight height | bmi <= skinny = “You are underweight.” | bmi <= normal = “You are normal.” | bmi <= fat = “You are fat.” | otherwise = “You are very fat.” where bmi = weight / height ^ 2 (skinny, normal, pat) = (18.5, 25.0, 30.0)
  • 17. where where 절 내부에서도 함수를 선언할 수 있으며, where 절 내부에 where절을 중첩해서 쓸 수도 있고, 함수를 만드는 데 필요한 문법들(패턴 매칭, 가드 등)도 모두 사용 가능합니다. calcFibos :: (Integral a) => [a] -> a calcFibos xs = [fibo x | x <- xs] where fibo 0 = 0 fibo 1 = 1 fibo n = fibo (n-1) + fibo (n-2)
  • 18. let in let in 표현식은 where 절과 비슷한 역할을 합니다. let (bindings) in (expression)의 형태를 하고 있으며, where이 뒤에 binding이 오는 반면 let은 binding이 앞에 온다는 차이점이 있습니다. cylinder :: (Num a) => a -> a -> a cylinder r h = let sideArea = 2 * pi * r * h topArea = pi * r^2 in sideArea + 2 * topArea let in 표현식은 let 절에서 바인딩한 값을 in 뒤에서 사용할 수 있습니다. 또 where절이 구문적인 구조인 반면 let in 표현식은 if문처럼 코드 상의 어디서든지 등장할 수 있습니다. 즉, let in 표현식은 그 자체로 평가되며 결과 값이 존재해야만 합니다.
  • 19. let in 한 줄에 여러 개의 바인딩을 하고 싶다면 세미콜론(;)을 이용합니다. Prelude> let a = 5 in a * a * a 125 Prelude> let squre x = x * x in (squre 5, squre 6) (25, 36) Prelude> let a = 100; b = 200; c = 300; in a + b + c 600 list comprehension에서도 let을 사용할 수 있습니다. 이 때 let은 바인딩의 역할만 합니다. Prelude> [f x|x<-[0..10],let f 0=0;f 1=1;f n=f (n-1)+f (n-2)] [0,1,1,2,3,5,8,13,21,34,55]
  • 20. case expression case 표현식은 명령형 언어의 switch - case 구문과 비슷한 개념이나, 훨씬 강력한 기능을 갖고 있습니다. case 표현식 역시 표현식이기 때문에 평가되는 값이고, 코드의 중간에 사용할 수 있습니다. 구문은 아래와 같은 구조를 갖고 있습니다. case expression of pattern -> result pattern -> result pattern -> result ... 함수 인자의 패턴 매칭과 굉장히 유사합니다. 특정 표현식의 패턴에 따른 결과 값을 case 표현식을 통해 나타낼 수 있습니다. 다만 함수에서의 패턴 매칭과는 다르게 case 표현식은 표현식이기 때문에 어디에서든지 사용가능합니다.
  • 21. case expression head’ :: [a] -> a head’ xs = case xs of [] -> error "Can’t call head on empty list." (x:_) -> x descList :: [a] -> String descList xs = "this List is " ++ case xs of [] -> "Empty List" [x]-> "Singleton List" xs -> "Long List"
  • 22. 연습 문제 • maximum 어떤 리스트가 주어져 있을 때, 리스트의 원소중 가장 큰 원소를 리턴하는 함수를 구현해 봅시다. 빈 리스트의 경우 error 함수를 사용해서 런타임 에러를 일으키게끔 만들어 보세요. • take 숫자와 리스트가 주어졌을 때, 리스트에서 처음부터 해당 숫자만큼의 원소를 잘라서 리턴하는 함수를 만들어 봅시다. 단, 숫자가 0이하인 경우 빈 리스트([])를 리턴해야 합니다. • zip 두 개의 리스트가 주어졌을 때 두 리스트의 원소 각각을 튜플로 짝지은 리스트를 리턴하는 함수를 만들어 봅시다. 위 함수는 모두 표준에 존재하는 함수입니다. 이름을 조금 다르게 작성하셔야 합니다.
  • 23. 연습 문제 • quickSort (* hard) 어떤 리스트가 주어져 있을 때, 그 리스트를 quickSort를 이용해 정렬하는 함수를 구현해봅시다. 처음에는 풀기 상당히 어려운 문제니 천천히 시간을 들여서 고민해봅시다.