SlideShare a Scribd company logo
1 of 33
Download to read offline
Haskell
Study
9. Monad & IO
Monad
Monad는 Applicative Functor에서 다시 한 발 더 나아간 개념입니다. Monad에서 핵심 역할을
하는 함수 >>=의 타입 서명은 다음과 같이 정의되어 있습니다.
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
즉, 모나드는 어떤 Context 속에 있는 값(m a)과, 일반적인 값을 받아서 특정 Context 속의 값을
반환하는 함수(a -> m b)가 주어졌을 때 Context 속에서 값을 꺼내 함수를 적용한 결과(m b)를
구할 수 있는 타입들의 집합입니다. >>= 함수는 bind라고 읽습니다.
Monad
모나드 타입 클래스는 다음과 같이 정의되어 있습니다.
class Monad m where
	return :: a -> m a
	(>>=) :: m a -> ( a -> m b ) -> m b
	(>>) :: m a -> m b -> m b
	 x >> y = x >>= _ -> y
	fail :: String -> m a
	 fail msg = error msg
Monad
하나씩 각각의 함수에 대해 살펴봅시다.
•	return
Applicative Functor에서 pure와 같은 역할을 하는 함수입니다. 어떤 값이 주어져있을 때 이 값을
해당 Context 속으로 집어넣는 역할을 합니다. 명령형 언어에서의 return과 헷갈릴 수 있는데 의미가
전혀 다르기 때문에 코드를 볼 때 주의하셔야 합니다.
•	>>=
앞에서 설명한 bind 함수입니다. Monad의 동작에서 핵심적인 역할을 합니다.
•	>>
지금은 크게 신경쓸 필요 없습니다. 이 후 설명하겠습니다.
•	fail
직접 사용하는 함수는 아니고, Monad 연산에서 뭔가 문제가 생겼을 때 컴파일러 측에서 사용하는
함수입니다. 크게 신경 쓸 필요 없습니다.
Monad
가장 간단한 예인 Maybe Monad를 예제로 삼아봅시다. Monad의 최소 정의는 return과 >>=
입니다. 이 두 함수만 잘 정의하면 Monad 타입 클래스에 속할 수 있습니다.
instance Monad Maybe where
	 return x = Just x
	 Nothing >>= f = Nothing
	 Just x >>= f = f x
	 fail _ = Nothing
return은 Applicative Functor에서의 pure와 완전히 동일하고, >>= 함수는 Context 속에 값이
없으면 함수와 상관없이 Nothing을, 그렇지 않으면 Context 속에서 값을 꺼내(Just x에서 x)
거기에 함수를 적용시킨 결과(f x)를 리턴하는 방식으로 동작합니다.
Monad
Maybe Monad의 사용 예제를 살펴봅시다.
Prelude> return "WHAT" :: Maybe String
Just "WHAT"
Prelude> Just 9 >>= x -> return (x*10)
Just 90
Prelude> Nothing >>= x -> return (x*10)
Nothing
Maybe Context 내부에 있는 값에 대해 연산을 하고 있음에도 불구하고 따로 패턴매칭을 하고
있지 않습니다. bind 함수(>>=)에 의해 Nothing이 인자로 들어온 경우 함수에 상관없이 자동으로
Nothing을 리턴하게 되고, 그렇지 않을 경우 Context 내부에서 값을 꺼내 인자로 넘기기
때문입니다.
Monad
Maybe Monad는 실패할 가능성이 있는 연산에 대해 굉장히 유용하게 사용할 수 있습니다. 다음
예제를 봅시다.
square :: Integer -> Maybe Integer
square n
	 | 0 <= n = Just ( n * n )
	 | otherwise = Nothing
square 함수는 양수인 숫자에 대해서만 그 값을 제곱해서 돌려주는 함수입니다. 그렇지 않을 경우 이
함수는 실패하게 되고, 결과로 Nothing을 반환합니다.
Monad
squareRoot :: Integer -> Maybe Integer
squareRoot n
	 | 0 <= n = squareRoot' 1
	 | otherwise = Nothing
	 where squareRoot' x
		| n > x * x = squareRoot' (x + 1)
		| n < x * x = Nothing
		| otherwise = Just x
squareRoot 함수는 어떤 숫자의 제곱근 값을 구합니다. 단, 그 숫자의 제곱근 값이 정수가 아닌 경우
Nothing을 반환합니다.
Monad
이제 이 두 함수를 이용해서, a^2 + b^2 의 제곱근을 구하는 함수를 작성한다고 해봅시다.
squareSumRoot :: Integer -> Integer -> Maybe Integer
squareSumRoot a b = case square a of
						Nothing -> Nothing
						Just as -> case square b of
										Nothing -> Nothing
										Just bs -> squareRoot (as + bs)
square 연산의 결과가 존재하는지 아닌지(함수가 실패하지 않았는지)를 먼저 검사를 해 봐야하기
때문에 코드가 굉장히 지저분해집니다. 함수를 여러 번 쓸 수록 기하급수적으로 복잡해지겠죠.
Monad
이런 형태의 코드는 명령형 언어에서도 심심찮게 찾아볼 수 있습니다. 앞의 함수를 C++로 짠다면 아마
다음과 같은 형태가 되겠죠.
//실패시 -1 리턴
int sqaureSumRoot(int a, int b)
{
	 int as = square(a);
	 if (as == -1) return -1;
	 int bs = square(b);
	 if (bs == -1) return -1;
	 return squareRoot (as + bs);
}
Monad
명령형 언어든 Haskell이든 저런식으로 코드를 작성하게 되면 굉장히 피곤하게 되고, 타입 시스템에
의해 예외 처리를 어느정도 강제적으로 하게되는 Haskell에 비해 대다수 명령형 언어의 경우 예외
처리를 깜빡하면 찾기 힘든 버그를 유발할 수도 있습니다. 즉, 실제 로직과는 크게 상관없는 예외
상황의 처리에 프로그래머가 상당히 많은 노력을 기울여야하는 짜증나는 상황에 처하게 된다는 거죠.
이럴 때 Maybe Monad를 사용하면 코드를 상당히 깔끔하게 바꿀 수 있습니다. Maybe Monad를
이용해 squreSumRoot 함수를 구현해봅시다.
squareSumRoot :: Integer -> Integer -> Maybe Integer
squaresumRoot a b = square a >>= (as ->
					 square b >>= (bs ->
					 squareRoot (as + bs))
Monad
squareSumRoot :: Integer -> Integer -> Maybe Integer
squareSumRoot a b = square a >>= (as ->
					 square b >>= (bs ->
					 squareRoot (as + bs))
당장은 이해하기 힘들게 생겨먹었지만 어쨌든 원래 코드보다는 훨씬 간단해졌습니다. Maybe
Monad를 쓰면 중간에 일일히 예외 처리 코드를 넣을 필요 없이 핵심적인 로직 코드만 작성할 수
있다는 장점이 생깁니다.
이제 위 코드가 어떤 의미인지, Maybe Monad가 어떤 식으로 동작하는지 차근차근 살펴봅시다.
Monad
squareSumRoot a b = square a >>= (as -> square b)
코드를 여기까지만 잘라서 동작이 어떻게 되는지 살펴봅시다.
square a
우선 square a의 값을 계산 합니다.
Monad
squareSumRoot a b = square a >>= (as -> square b)
코드를 여기까지만 잘라서 동작이 어떻게 되는지 살펴봅시다.
square a Just as
Nothing
square a의 계산 결과는 위의 두 가지 중
하나일 것입니다. 제대로 계산할 수 있는 경우
Just as 형태의 꼴, 그렇지 않을 경우 계산에
실패해서 Nothing을 리턴하겠죠.
Monad
squareSumRoot a b = square a >>= (as -> square b)
코드를 여기까지만 잘라서 동작이 어떻게 되는지 살펴봅시다.
square a
>>=
Just as
Nothing
bind
이제 square a의 연산 결과가
>>=(bind) 함수에 의해 다음 람다
(as -> square b)의 인자로
넘어가게 됩니다.
Monad
squareSumRoot a b = square a >>= (as -> square b)
코드를 여기까지만 잘라서 동작이 어떻게 되는지 살펴봅시다.
square a
>>=
Just as
Nothing
bind
as -> square b
square a 연산이 성공한 경우, Just as
에서 as 값만 꺼내서 두 번째 함수의 인자로
넘깁니다. 여기서 다시 sqaure b 연산을
하고 있으니, 이 함수를 실행하면 square b
의 결과 값을 리턴하겠죠.
Monad
squareSumRoot a b = square a >>= (as -> square b)
코드를 여기까지만 잘라서 동작이 어떻게 되는지 살펴봅시다.
square a
>>=
Just as
Nothing
bind
as -> square b
Nothing
만약 square a의 연산 결과가 실패했다면,
이 함수는 이후의 람다를 실행하지 않고
단순히 Nothing을 리턴할 것입니다(>>=
함수의 구현에 의해)
Monad
squareSumRoot a b = square a >>= (as ->
					 square b >>= (bs ->
					 squareRoot (as + bs))
이제 이어서 전체 코드를 봅시다.
square a
>>=
Just as
Nothing
bind
as -> square b
Nothing
Monad
squareSumRoot a b = square a >>= (as ->
					 square b >>= (bs ->
					 squareRoot (as + bs))
이제 이어서 전체 코드를 봅시다.
square a
>>=
Just as
Nothing
bind
as -> square b
Nothing
square b
이어서 두번째줄(빨간색)을 보면, square b
의 결과를 구한 후 다시 그 결과를 다음 람다와
bind(>>=)하고 있습니다.
Monad
squareSumRoot a b = square a >>= (as ->
					 square b >>= (bs ->
					 squareRoot (as + bs))
이제 이어서 전체 코드를 봅시다.
square a
>>=
Just as
Nothing
bind
as -> square b
Nothing
square b Just bs
Nothing
이 때도 역시 square b 함수의
결과는 다음 두 가지가 되겠죠.
Monad
squareSumRoot a b = square a >>= (as ->
					 square b >>= (bs ->
					 squareRoot (as + bs))
이제 이어서 전체 코드를 봅시다.
square a
>>=
Just as
Nothing
bind
as -> square b
Nothing
square b
>>=
Just bs
Nothing
bind
bs -> squareRoot(as+bs)
square b에 성공했을 경우 그 결과 Just bs에서
bs만 꺼내 다음 람다에 넘깁니다. 여기서 앞서
구한 as와 bs를 더한 값의 제곱근을 구하죠.
Monad
squareSumRoot a b = square a >>= (as ->
					 square b >>= (bs ->
					 squareRoot (as + bs))
이제 이어서 전체 코드를 봅시다.
square a
>>=
Just as
Nothing
bind
as -> square b
Nothing
square b
>>=
Just bs
Nothing
bind
bs -> squareRoot(as+bs)
Nothing
물론 실패하면 그냥
Nothing을 리턴합니다.
Monad
square a
>>=
Just as
Nothing
bind
as -> square b
Nothing
square b
>>=
Just bs
Nothing
bind
bs -> squareRoot(as+bs)
Nothing
이 전체 흐름을 잘 보시면 앞에서 case expression을 이용해 작성한 것과 별반 다를 게 없다는 것을
알 수 있습니다. 다만, Monad의 경우 >>= 함수를 통해 프로그래머가 신경 쓸 필요 없이 예외 처리를
자동으로 해준다는 점만이 다를 뿐이죠.
do notation
Monad는 분명 좋은 개념이지만, 익숙하지 않은 사람이 봤을 때 코드를 읽기 힘들다는 단점이
있습니다.
Haskell에서는 모나드가 굉장히 많이 사용되기 때문에, 이런 표기 문제를 해결하기 위해 do
표기법이라는 문법을 지원합니다. 앞의 모나드를 사용한 함수 코드는 do 표기법을 이용해서 아래와
같이 쓸 수 있습니다.
squareSumRoot :: Integer -> Integer -> Maybe Integer
squareSumRoot a b = do
		as <- square a
		bs <- square b
		squareRoot (as + bs)
do notation
squareSumRoot a b =
		 square a >>= (as ->
		 square b >>= (bs ->
		squareRoot (as + bs))
squareSumRoot a b = do
		as <- square a
		bs <- square b
		squareRoot (as + bs)
do 표기법을 쓰지 않은 경우와 do 표기법을 쓴 두 가지 경우의 비교입니다. do 표기법에서 <-는
>>=(bind)의 역할을 합니다.
(result) <- (function call)
이 때 바인딩되는 결과값은 Context내부의 값입니다. as <- square a에서 square a의 결과가
Just 9라면 as에는 9가 바인딩된다는 의미입니다. 람다에서 as -> 에서 인자인 as를 합쳐서
as <- square a 형태가 되는 거라고 생각하시면 조금 이해하기 편할지도 모르겠네요.
>>
monad의 >> 함수는 단순히 이전의 연산 결과를 내버려두고 다른 연산을 수행하는 역할을 합니다.
이전 연산과 별 상관 없는 다른 연산을 할 때 사용할 수 있죠. do notataion은 다음의 1대1 변환을
기준으로 컴파일됩니다.
do e1
e2
는 e1 >> e2와 동일합니다.
do p <- e1
e2
는
e1 >>= (v -> case v of p -> e2
						 _ -> fail "s") 와 동일합니다.
fail
e1 >>= (v -> case v of p -> e2
						 _ -> fail "s"
이 코드를 보면 fail 함수가 쓰이고 있는 걸 알 수 있습니다. 저기서 "s"는 오류 상황에 맞는 어떤
텍스트를 의미합니다. 결국 fail 함수는 do notation 내부에서 어떤 잘못된 결과가 나왔을 때 그에
따른 처리를 하기 위한 함수라고 볼 수 있죠. 그리고 Maybe Monad에서 fail 함수는 다음과 같이
정의되어 있습니다.
fail _ = Nothing
따라서 do notation 내부에서 어떤 잘못된 결과가 발생했을 때 fail 함수가 호출이 되고, 이는
Nothing을 리턴하므로 연산 도중 뭔가 실패했을 때 Nothing을 반환하고 끝이 나게 되는 것입니다.
List Monad
List 역시 Monad 입니다. Applicative Functor에서 말했듯이, List Monad는 비결정성을
의미합니다. List Monad는 다음과 같이 정의되어 있습니다.
instance Monad [] where
	 return x = [x]
	 xs >>= f = concat (map f xs)
	 fail _ = []
리스트 모나드는 바인딩을 할 때(>>=) 주어진 함수를 map의 모든 원소에 적용한 후 그걸 합치는
형태로 동작함을 알 수 있습니다. 그리고 fail 함수가 []를 리턴하니 do notation 내부에서 뭔가
문제가 생겼을 때 []를 리턴하고 끝날 것이라는 것도 알 수 있죠.
List Monad
List Monad의 사용 예제를 살펴봅시다.
Prelude> [3, 4, 5] >>= x -> [x, -x]
[3, -3, 4, -4, 5, -5]
Prelude> [1,2] >>= n -> ['a','b'] >>= ch -> return (n, ch)
[(1,'a'),(1,'b'),(2,'a'),(2,'b')]
List Monad
do notation 내부에서 let 키워드를 사용할 수 있습니다. 그리고 List Monad의 do notation과 List
comprehension은 사실 완전히 동일한 것입니다.
listOfTuples = do
	n <- [1,2]
	 let chs = ['a','b']
	ch <- chs
	 return (n, ch)
listOfTuples' = [ (n, ch) | n <- [1,2], ch <- ['a','b'] ]
Monad laws
Monad 역시 Applicative Functor와 마찬가지로 반드시 지켜야하는 규칙이 있습니다. 이 것도
자세한 내용은 생략하지만, 필요할 때 찾아서 깊이 있게 공부해보시는 것을 권장합니다.
•	Left Identity
return a >>= f ≡ f a
•	Right Identity
m >>= return ≡ m
•	Associativity
(m >>= f) >>= g ≡ m >>= (x -> f x >>= g)
IO Monad
Haskell에서는 IO 작업이 Monad로 취급됩니다. IO Monad는 Side Effect가 발생할 수 있는 연산을
뜻하는 Context입니다. Haskell은 IO Monad를 통해 모든 Side Effect가 발생할 수 있는 연산과
그렇지 않은 연산을 완전히 분리합니다.
Haskell의 main 함수는 IO () 를 리턴합니다.
main :: IO ()
main = do
	putStrLn "Hello, World!"
모든 IO 연산은 결과 값으로 IO 컨텍스트 내부의 값을 리턴하기 때문에 주로 do notation을 써서
코딩하게 됩니다. 위 코드를 파일에 저장하고 cmd 창에서 ghc (file name).hs 를 실행하면 실행
파일이 생성됩니다. 실행해서 결과를 확인해봅시다.
IO Monad
간단하게 값을 입력 받아서 그대로 echo 해주고 종료하는 프로그램을 만들어 봅시다.
main = do
	str <- getLine
	 putStrLn str
getLine 함수는 IO String 타입을 갖고 있습니다. 이 함수는 외부에서 값을 입력받아 그걸 IO
Context로 감싸서 결과를 돌려줍니다. side effect를 갖고 있는 IO 함수이기 때문이죠. putStrLn
역시 화면에 값을 출력하는 side effect를 갖고 있는 IO 함수기 때문에 IO () 타입을 가집니다.
IO와 관련해서도 굉장히 다양한 함수들이 있습니다. 역시 Hoogle 등에서 System.IO 모듈의 함수를
한 번 살펴보시는 걸 권장합니다.

More Related Content

What's hot

Virtual function in C++ Pure Virtual Function
Virtual function in C++ Pure Virtual Function Virtual function in C++ Pure Virtual Function
Virtual function in C++ Pure Virtual Function Kamlesh Makvana
 
Data abstraction and object orientation
Data abstraction and object orientationData abstraction and object orientation
Data abstraction and object orientationHoang Nguyen
 
Constructor in java
Constructor in javaConstructor in java
Constructor in javaHitesh Kumar
 
Javascript conditional statements
Javascript conditional statementsJavascript conditional statements
Javascript conditional statementsnobel mujuji
 
Object Oriented Programming In JavaScript
Object Oriented Programming In JavaScriptObject Oriented Programming In JavaScript
Object Oriented Programming In JavaScriptForziatech
 
Vector class in C++
Vector class in C++Vector class in C++
Vector class in C++Jawad Khan
 
The lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsThe lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsScott Wlaschin
 
Wrapper class (130240116056)
Wrapper class (130240116056)Wrapper class (130240116056)
Wrapper class (130240116056)Akshay soni
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsPhilip Schwarz
 
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2Philip Schwarz
 
Exception Handling in C++
Exception Handling in C++Exception Handling in C++
Exception Handling in C++Deepak Tathe
 
Constructor in Java - ITVoyagers
Constructor in Java - ITVoyagersConstructor in Java - ITVoyagers
Constructor in Java - ITVoyagersITVoyagers
 

What's hot (20)

Virtual function in C++ Pure Virtual Function
Virtual function in C++ Pure Virtual Function Virtual function in C++ Pure Virtual Function
Virtual function in C++ Pure Virtual Function
 
Data abstraction and object orientation
Data abstraction and object orientationData abstraction and object orientation
Data abstraction and object orientation
 
Operator overloading
Operator overloadingOperator overloading
Operator overloading
 
PHP - Introduction to PHP Error Handling
PHP -  Introduction to PHP Error HandlingPHP -  Introduction to PHP Error Handling
PHP - Introduction to PHP Error Handling
 
Constructor in java
Constructor in javaConstructor in java
Constructor in java
 
Lecture 18 - Pointers
Lecture 18 - PointersLecture 18 - Pointers
Lecture 18 - Pointers
 
Javascript conditional statements
Javascript conditional statementsJavascript conditional statements
Javascript conditional statements
 
Java Tokens
Java  TokensJava  Tokens
Java Tokens
 
JSON Schema Design
JSON Schema DesignJSON Schema Design
JSON Schema Design
 
Object Oriented Programming In JavaScript
Object Oriented Programming In JavaScriptObject Oriented Programming In JavaScript
Object Oriented Programming In JavaScript
 
Vector class in C++
Vector class in C++Vector class in C++
Vector class in C++
 
The lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsThe lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of tests
 
Wrapper class (130240116056)
Wrapper class (130240116056)Wrapper class (130240116056)
Wrapper class (130240116056)
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
Bubble Sort
Bubble SortBubble Sort
Bubble Sort
 
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 2
 
Exception Handling in C++
Exception Handling in C++Exception Handling in C++
Exception Handling in C++
 
JSON and REST
JSON and RESTJSON and REST
JSON and REST
 
Constructor in Java - ITVoyagers
Constructor in Java - ITVoyagersConstructor in Java - ITVoyagers
Constructor in Java - ITVoyagers
 
2 Object Oriented Programming
2 Object Oriented Programming2 Object Oriented Programming
2 Object Oriented Programming
 

Viewers also liked

1단원 업로드용
1단원 업로드용1단원 업로드용
1단원 업로드용wallswalls
 
[INFO2014]02_Definition
[INFO2014]02_Definition[INFO2014]02_Definition
[INFO2014]02_DefinitionJY LEE
 
에스티마의 베이징 방문기
에스티마의 베이징 방문기에스티마의 베이징 방문기
에스티마의 베이징 방문기StartupAlliance
 
Out-Think | Marketing Start-ups, From The Ground Up
Out-Think | Marketing Start-ups, From The Ground UpOut-Think | Marketing Start-ups, From The Ground Up
Out-Think | Marketing Start-ups, From The Ground UpBen Grossman
 
넘쳐나는 정보 소화 노하우
넘쳐나는 정보 소화 노하우넘쳐나는 정보 소화 노하우
넘쳐나는 정보 소화 노하우종빈 오
 
201313101 이상희 기말고사
201313101 이상희 기말고사201313101 이상희 기말고사
201313101 이상희 기말고사Sanghee Lee
 
Sw교육 이야기 연구학교연수
Sw교육 이야기 연구학교연수Sw교육 이야기 연구학교연수
Sw교육 이야기 연구학교연수Sangsu Song
 
Giveyourmessgae 파이널
Giveyourmessgae 파이널Giveyourmessgae 파이널
Giveyourmessgae 파이널예슬 이
 
아꿈사.C++ api 디자인.20140315 a
아꿈사.C++ api 디자인.20140315 a아꿈사.C++ api 디자인.20140315 a
아꿈사.C++ api 디자인.20140315 aChoonghyun Yang
 
[멘토링] 건축공학부 소개 PPT
[멘토링] 건축공학부 소개 PPT[멘토링] 건축공학부 소개 PPT
[멘토링] 건축공학부 소개 PPTInhye Lee
 
IQ Work Hacks - Power Dressing (For Women)
IQ Work Hacks - Power Dressing (For Women)IQ Work Hacks - Power Dressing (For Women)
IQ Work Hacks - Power Dressing (For Women)InterQuest Group
 
객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)Seung-June Lee
 

Viewers also liked (20)

Korean
KoreanKorean
Korean
 
1단원 업로드용
1단원 업로드용1단원 업로드용
1단원 업로드용
 
최종Ppt
최종Ppt최종Ppt
최종Ppt
 
[INFO2014]02_Definition
[INFO2014]02_Definition[INFO2014]02_Definition
[INFO2014]02_Definition
 
Bs camp
Bs campBs camp
Bs camp
 
good afternoon
good afternoongood afternoon
good afternoon
 
에스티마의 베이징 방문기
에스티마의 베이징 방문기에스티마의 베이징 방문기
에스티마의 베이징 방문기
 
Media 5a new
Media 5a newMedia 5a new
Media 5a new
 
Out-Think | Marketing Start-ups, From The Ground Up
Out-Think | Marketing Start-ups, From The Ground UpOut-Think | Marketing Start-ups, From The Ground Up
Out-Think | Marketing Start-ups, From The Ground Up
 
넘쳐나는 정보 소화 노하우
넘쳐나는 정보 소화 노하우넘쳐나는 정보 소화 노하우
넘쳐나는 정보 소화 노하우
 
201313101 이상희 기말고사
201313101 이상희 기말고사201313101 이상희 기말고사
201313101 이상희 기말고사
 
최종Google3
최종Google3최종Google3
최종Google3
 
Sw교육 이야기 연구학교연수
Sw교육 이야기 연구학교연수Sw교육 이야기 연구학교연수
Sw교육 이야기 연구학교연수
 
기업문화
기업문화기업문화
기업문화
 
Giveyourmessgae 파이널
Giveyourmessgae 파이널Giveyourmessgae 파이널
Giveyourmessgae 파이널
 
아꿈사.C++ api 디자인.20140315 a
아꿈사.C++ api 디자인.20140315 a아꿈사.C++ api 디자인.20140315 a
아꿈사.C++ api 디자인.20140315 a
 
RESTful API
RESTful APIRESTful API
RESTful API
 
[멘토링] 건축공학부 소개 PPT
[멘토링] 건축공학부 소개 PPT[멘토링] 건축공학부 소개 PPT
[멘토링] 건축공학부 소개 PPT
 
IQ Work Hacks - Power Dressing (For Women)
IQ Work Hacks - Power Dressing (For Women)IQ Work Hacks - Power Dressing (For Women)
IQ Work Hacks - Power Dressing (For Women)
 
객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)
 

Similar to Haskell study 9

Haskell study 14
Haskell study 14Haskell study 14
Haskell study 14Nam Hyeonuk
 
Haskell study 15
Haskell study 15Haskell study 15
Haskell study 15Nam Hyeonuk
 
Haskell study 13
Haskell study 13Haskell study 13
Haskell study 13Nam Hyeonuk
 
RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수
RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수
RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수Aiden Seonghak Hong
 
[컴퓨터비전과 인공지능] 6. 역전파 2
[컴퓨터비전과 인공지능] 6. 역전파 2[컴퓨터비전과 인공지능] 6. 역전파 2
[컴퓨터비전과 인공지능] 6. 역전파 2jdo
 
하스켈 프로그래밍 입문 2
하스켈 프로그래밍 입문 2하스켈 프로그래밍 입문 2
하스켈 프로그래밍 입문 2Kwang Yul Seo
 
병렬 프로그래밍2
병렬 프로그래밍2병렬 프로그래밍2
병렬 프로그래밍2준혁 이
 
Haskell study 10
Haskell study 10Haskell study 10
Haskell study 10Nam Hyeonuk
 
하스켈 모나드
하스켈 모나드하스켈 모나드
하스켈 모나드Kwang Yul Seo
 
R 프로그래밍 기본 문법
R 프로그래밍 기본 문법R 프로그래밍 기본 문법
R 프로그래밍 기본 문법Terry Cho
 
Java jungsuk3 ch14_lambda_stream
Java jungsuk3 ch14_lambda_streamJava jungsuk3 ch14_lambda_stream
Java jungsuk3 ch14_lambda_stream성 남궁
 
하스켈 프로그래밍 입문
하스켈 프로그래밍 입문하스켈 프로그래밍 입문
하스켈 프로그래밍 입문Kwang Yul Seo
 
자바로 Mnist 구현하고_스프링웹서버붙이기
자바로 Mnist 구현하고_스프링웹서버붙이기자바로 Mnist 구현하고_스프링웹서버붙이기
자바로 Mnist 구현하고_스프링웹서버붙이기라한사 아
 
Lua 문법 -함수
Lua 문법 -함수Lua 문법 -함수
Lua 문법 -함수Jaehoon Lee
 
Project#2말의여행 Hwp
Project#2말의여행 HwpProject#2말의여행 Hwp
Project#2말의여행 HwpKimjeongmoo
 
자바스크립트.
자바스크립트.자바스크립트.
자바스크립트.Deoc Jin
 
일단 시작하는 코틀린
일단 시작하는 코틀린일단 시작하는 코틀린
일단 시작하는 코틀린Park JoongSoo
 
스위프트 성능 이해하기
스위프트 성능 이해하기스위프트 성능 이해하기
스위프트 성능 이해하기Yongha Yoo
 

Similar to Haskell study 9 (20)

Haskell study 14
Haskell study 14Haskell study 14
Haskell study 14
 
Haskell study 15
Haskell study 15Haskell study 15
Haskell study 15
 
Haskell study 13
Haskell study 13Haskell study 13
Haskell study 13
 
RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수
RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수
RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수
 
7장매크로
7장매크로7장매크로
7장매크로
 
[컴퓨터비전과 인공지능] 6. 역전파 2
[컴퓨터비전과 인공지능] 6. 역전파 2[컴퓨터비전과 인공지능] 6. 역전파 2
[컴퓨터비전과 인공지능] 6. 역전파 2
 
하스켈 프로그래밍 입문 2
하스켈 프로그래밍 입문 2하스켈 프로그래밍 입문 2
하스켈 프로그래밍 입문 2
 
병렬 프로그래밍2
병렬 프로그래밍2병렬 프로그래밍2
병렬 프로그래밍2
 
Haskell study 10
Haskell study 10Haskell study 10
Haskell study 10
 
하스켈 모나드
하스켈 모나드하스켈 모나드
하스켈 모나드
 
R 프로그래밍 기본 문법
R 프로그래밍 기본 문법R 프로그래밍 기본 문법
R 프로그래밍 기본 문법
 
Java jungsuk3 ch14_lambda_stream
Java jungsuk3 ch14_lambda_streamJava jungsuk3 ch14_lambda_stream
Java jungsuk3 ch14_lambda_stream
 
하스켈 프로그래밍 입문
하스켈 프로그래밍 입문하스켈 프로그래밍 입문
하스켈 프로그래밍 입문
 
자바로 Mnist 구현하고_스프링웹서버붙이기
자바로 Mnist 구현하고_스프링웹서버붙이기자바로 Mnist 구현하고_스프링웹서버붙이기
자바로 Mnist 구현하고_스프링웹서버붙이기
 
Lua 문법 -함수
Lua 문법 -함수Lua 문법 -함수
Lua 문법 -함수
 
Project#2말의여행 Hwp
Project#2말의여행 HwpProject#2말의여행 Hwp
Project#2말의여행 Hwp
 
자바스크립트.
자바스크립트.자바스크립트.
자바스크립트.
 
일단 시작하는 코틀린
일단 시작하는 코틀린일단 시작하는 코틀린
일단 시작하는 코틀린
 
Ch08
Ch08Ch08
Ch08
 
스위프트 성능 이해하기
스위프트 성능 이해하기스위프트 성능 이해하기
스위프트 성능 이해하기
 

More from Nam Hyeonuk

Next 게임 실전 프로젝트 슬라이드
Next 게임 실전 프로젝트 슬라이드Next 게임 실전 프로젝트 슬라이드
Next 게임 실전 프로젝트 슬라이드Nam Hyeonuk
 
Haskell study 11
Haskell study 11Haskell study 11
Haskell study 11Nam Hyeonuk
 
Memory & object pooling
Memory & object poolingMemory & object pooling
Memory & object poolingNam Hyeonuk
 
Iocp 기본 구조 이해
Iocp 기본 구조 이해Iocp 기본 구조 이해
Iocp 기본 구조 이해Nam Hyeonuk
 
Tcp ip & io model
Tcp ip & io modelTcp ip & io model
Tcp ip & io modelNam Hyeonuk
 
Effective c++ chapter 1,2 요약
Effective c++ chapter 1,2 요약Effective c++ chapter 1,2 요약
Effective c++ chapter 1,2 요약Nam Hyeonuk
 
구문과 의미론(정적 의미론까지)
구문과 의미론(정적 의미론까지)구문과 의미론(정적 의미론까지)
구문과 의미론(정적 의미론까지)Nam Hyeonuk
 
Stl vector, list, map
Stl vector, list, mapStl vector, list, map
Stl vector, list, mapNam Hyeonuk
 
Age Of Empires II : Age Of Kings Postmotem
Age Of Empires II : Age Of Kings PostmotemAge Of Empires II : Age Of Kings Postmotem
Age Of Empires II : Age Of Kings PostmotemNam Hyeonuk
 

More from Nam Hyeonuk (16)

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

Haskell study 9

  • 2. Monad Monad는 Applicative Functor에서 다시 한 발 더 나아간 개념입니다. Monad에서 핵심 역할을 하는 함수 >>=의 타입 서명은 다음과 같이 정의되어 있습니다. (>>=) :: (Monad m) => m a -> (a -> m b) -> m b 즉, 모나드는 어떤 Context 속에 있는 값(m a)과, 일반적인 값을 받아서 특정 Context 속의 값을 반환하는 함수(a -> m b)가 주어졌을 때 Context 속에서 값을 꺼내 함수를 적용한 결과(m b)를 구할 수 있는 타입들의 집합입니다. >>= 함수는 bind라고 읽습니다.
  • 3. Monad 모나드 타입 클래스는 다음과 같이 정의되어 있습니다. class Monad m where return :: a -> m a (>>=) :: m a -> ( a -> m b ) -> m b (>>) :: m a -> m b -> m b x >> y = x >>= _ -> y fail :: String -> m a fail msg = error msg
  • 4. Monad 하나씩 각각의 함수에 대해 살펴봅시다. • return Applicative Functor에서 pure와 같은 역할을 하는 함수입니다. 어떤 값이 주어져있을 때 이 값을 해당 Context 속으로 집어넣는 역할을 합니다. 명령형 언어에서의 return과 헷갈릴 수 있는데 의미가 전혀 다르기 때문에 코드를 볼 때 주의하셔야 합니다. • >>= 앞에서 설명한 bind 함수입니다. Monad의 동작에서 핵심적인 역할을 합니다. • >> 지금은 크게 신경쓸 필요 없습니다. 이 후 설명하겠습니다. • fail 직접 사용하는 함수는 아니고, Monad 연산에서 뭔가 문제가 생겼을 때 컴파일러 측에서 사용하는 함수입니다. 크게 신경 쓸 필요 없습니다.
  • 5. Monad 가장 간단한 예인 Maybe Monad를 예제로 삼아봅시다. Monad의 최소 정의는 return과 >>= 입니다. 이 두 함수만 잘 정의하면 Monad 타입 클래스에 속할 수 있습니다. instance Monad Maybe where return x = Just x Nothing >>= f = Nothing Just x >>= f = f x fail _ = Nothing return은 Applicative Functor에서의 pure와 완전히 동일하고, >>= 함수는 Context 속에 값이 없으면 함수와 상관없이 Nothing을, 그렇지 않으면 Context 속에서 값을 꺼내(Just x에서 x) 거기에 함수를 적용시킨 결과(f x)를 리턴하는 방식으로 동작합니다.
  • 6. Monad Maybe Monad의 사용 예제를 살펴봅시다. Prelude> return "WHAT" :: Maybe String Just "WHAT" Prelude> Just 9 >>= x -> return (x*10) Just 90 Prelude> Nothing >>= x -> return (x*10) Nothing Maybe Context 내부에 있는 값에 대해 연산을 하고 있음에도 불구하고 따로 패턴매칭을 하고 있지 않습니다. bind 함수(>>=)에 의해 Nothing이 인자로 들어온 경우 함수에 상관없이 자동으로 Nothing을 리턴하게 되고, 그렇지 않을 경우 Context 내부에서 값을 꺼내 인자로 넘기기 때문입니다.
  • 7. Monad Maybe Monad는 실패할 가능성이 있는 연산에 대해 굉장히 유용하게 사용할 수 있습니다. 다음 예제를 봅시다. square :: Integer -> Maybe Integer square n | 0 <= n = Just ( n * n ) | otherwise = Nothing square 함수는 양수인 숫자에 대해서만 그 값을 제곱해서 돌려주는 함수입니다. 그렇지 않을 경우 이 함수는 실패하게 되고, 결과로 Nothing을 반환합니다.
  • 8. Monad squareRoot :: Integer -> Maybe Integer squareRoot n | 0 <= n = squareRoot' 1 | otherwise = Nothing where squareRoot' x | n > x * x = squareRoot' (x + 1) | n < x * x = Nothing | otherwise = Just x squareRoot 함수는 어떤 숫자의 제곱근 값을 구합니다. 단, 그 숫자의 제곱근 값이 정수가 아닌 경우 Nothing을 반환합니다.
  • 9. Monad 이제 이 두 함수를 이용해서, a^2 + b^2 의 제곱근을 구하는 함수를 작성한다고 해봅시다. squareSumRoot :: Integer -> Integer -> Maybe Integer squareSumRoot a b = case square a of Nothing -> Nothing Just as -> case square b of Nothing -> Nothing Just bs -> squareRoot (as + bs) square 연산의 결과가 존재하는지 아닌지(함수가 실패하지 않았는지)를 먼저 검사를 해 봐야하기 때문에 코드가 굉장히 지저분해집니다. 함수를 여러 번 쓸 수록 기하급수적으로 복잡해지겠죠.
  • 10. Monad 이런 형태의 코드는 명령형 언어에서도 심심찮게 찾아볼 수 있습니다. 앞의 함수를 C++로 짠다면 아마 다음과 같은 형태가 되겠죠. //실패시 -1 리턴 int sqaureSumRoot(int a, int b) { int as = square(a); if (as == -1) return -1; int bs = square(b); if (bs == -1) return -1; return squareRoot (as + bs); }
  • 11. Monad 명령형 언어든 Haskell이든 저런식으로 코드를 작성하게 되면 굉장히 피곤하게 되고, 타입 시스템에 의해 예외 처리를 어느정도 강제적으로 하게되는 Haskell에 비해 대다수 명령형 언어의 경우 예외 처리를 깜빡하면 찾기 힘든 버그를 유발할 수도 있습니다. 즉, 실제 로직과는 크게 상관없는 예외 상황의 처리에 프로그래머가 상당히 많은 노력을 기울여야하는 짜증나는 상황에 처하게 된다는 거죠. 이럴 때 Maybe Monad를 사용하면 코드를 상당히 깔끔하게 바꿀 수 있습니다. Maybe Monad를 이용해 squreSumRoot 함수를 구현해봅시다. squareSumRoot :: Integer -> Integer -> Maybe Integer squaresumRoot a b = square a >>= (as -> square b >>= (bs -> squareRoot (as + bs))
  • 12. Monad squareSumRoot :: Integer -> Integer -> Maybe Integer squareSumRoot a b = square a >>= (as -> square b >>= (bs -> squareRoot (as + bs)) 당장은 이해하기 힘들게 생겨먹었지만 어쨌든 원래 코드보다는 훨씬 간단해졌습니다. Maybe Monad를 쓰면 중간에 일일히 예외 처리 코드를 넣을 필요 없이 핵심적인 로직 코드만 작성할 수 있다는 장점이 생깁니다. 이제 위 코드가 어떤 의미인지, Maybe Monad가 어떤 식으로 동작하는지 차근차근 살펴봅시다.
  • 13. Monad squareSumRoot a b = square a >>= (as -> square b) 코드를 여기까지만 잘라서 동작이 어떻게 되는지 살펴봅시다. square a 우선 square a의 값을 계산 합니다.
  • 14. Monad squareSumRoot a b = square a >>= (as -> square b) 코드를 여기까지만 잘라서 동작이 어떻게 되는지 살펴봅시다. square a Just as Nothing square a의 계산 결과는 위의 두 가지 중 하나일 것입니다. 제대로 계산할 수 있는 경우 Just as 형태의 꼴, 그렇지 않을 경우 계산에 실패해서 Nothing을 리턴하겠죠.
  • 15. Monad squareSumRoot a b = square a >>= (as -> square b) 코드를 여기까지만 잘라서 동작이 어떻게 되는지 살펴봅시다. square a >>= Just as Nothing bind 이제 square a의 연산 결과가 >>=(bind) 함수에 의해 다음 람다 (as -> square b)의 인자로 넘어가게 됩니다.
  • 16. Monad squareSumRoot a b = square a >>= (as -> square b) 코드를 여기까지만 잘라서 동작이 어떻게 되는지 살펴봅시다. square a >>= Just as Nothing bind as -> square b square a 연산이 성공한 경우, Just as 에서 as 값만 꺼내서 두 번째 함수의 인자로 넘깁니다. 여기서 다시 sqaure b 연산을 하고 있으니, 이 함수를 실행하면 square b 의 결과 값을 리턴하겠죠.
  • 17. Monad squareSumRoot a b = square a >>= (as -> square b) 코드를 여기까지만 잘라서 동작이 어떻게 되는지 살펴봅시다. square a >>= Just as Nothing bind as -> square b Nothing 만약 square a의 연산 결과가 실패했다면, 이 함수는 이후의 람다를 실행하지 않고 단순히 Nothing을 리턴할 것입니다(>>= 함수의 구현에 의해)
  • 18. Monad squareSumRoot a b = square a >>= (as -> square b >>= (bs -> squareRoot (as + bs)) 이제 이어서 전체 코드를 봅시다. square a >>= Just as Nothing bind as -> square b Nothing
  • 19. Monad squareSumRoot a b = square a >>= (as -> square b >>= (bs -> squareRoot (as + bs)) 이제 이어서 전체 코드를 봅시다. square a >>= Just as Nothing bind as -> square b Nothing square b 이어서 두번째줄(빨간색)을 보면, square b 의 결과를 구한 후 다시 그 결과를 다음 람다와 bind(>>=)하고 있습니다.
  • 20. Monad squareSumRoot a b = square a >>= (as -> square b >>= (bs -> squareRoot (as + bs)) 이제 이어서 전체 코드를 봅시다. square a >>= Just as Nothing bind as -> square b Nothing square b Just bs Nothing 이 때도 역시 square b 함수의 결과는 다음 두 가지가 되겠죠.
  • 21. Monad squareSumRoot a b = square a >>= (as -> square b >>= (bs -> squareRoot (as + bs)) 이제 이어서 전체 코드를 봅시다. square a >>= Just as Nothing bind as -> square b Nothing square b >>= Just bs Nothing bind bs -> squareRoot(as+bs) square b에 성공했을 경우 그 결과 Just bs에서 bs만 꺼내 다음 람다에 넘깁니다. 여기서 앞서 구한 as와 bs를 더한 값의 제곱근을 구하죠.
  • 22. Monad squareSumRoot a b = square a >>= (as -> square b >>= (bs -> squareRoot (as + bs)) 이제 이어서 전체 코드를 봅시다. square a >>= Just as Nothing bind as -> square b Nothing square b >>= Just bs Nothing bind bs -> squareRoot(as+bs) Nothing 물론 실패하면 그냥 Nothing을 리턴합니다.
  • 23. Monad square a >>= Just as Nothing bind as -> square b Nothing square b >>= Just bs Nothing bind bs -> squareRoot(as+bs) Nothing 이 전체 흐름을 잘 보시면 앞에서 case expression을 이용해 작성한 것과 별반 다를 게 없다는 것을 알 수 있습니다. 다만, Monad의 경우 >>= 함수를 통해 프로그래머가 신경 쓸 필요 없이 예외 처리를 자동으로 해준다는 점만이 다를 뿐이죠.
  • 24. do notation Monad는 분명 좋은 개념이지만, 익숙하지 않은 사람이 봤을 때 코드를 읽기 힘들다는 단점이 있습니다. Haskell에서는 모나드가 굉장히 많이 사용되기 때문에, 이런 표기 문제를 해결하기 위해 do 표기법이라는 문법을 지원합니다. 앞의 모나드를 사용한 함수 코드는 do 표기법을 이용해서 아래와 같이 쓸 수 있습니다. squareSumRoot :: Integer -> Integer -> Maybe Integer squareSumRoot a b = do as <- square a bs <- square b squareRoot (as + bs)
  • 25. do notation squareSumRoot a b = square a >>= (as -> square b >>= (bs -> squareRoot (as + bs)) squareSumRoot a b = do as <- square a bs <- square b squareRoot (as + bs) do 표기법을 쓰지 않은 경우와 do 표기법을 쓴 두 가지 경우의 비교입니다. do 표기법에서 <-는 >>=(bind)의 역할을 합니다. (result) <- (function call) 이 때 바인딩되는 결과값은 Context내부의 값입니다. as <- square a에서 square a의 결과가 Just 9라면 as에는 9가 바인딩된다는 의미입니다. 람다에서 as -> 에서 인자인 as를 합쳐서 as <- square a 형태가 되는 거라고 생각하시면 조금 이해하기 편할지도 모르겠네요.
  • 26. >> monad의 >> 함수는 단순히 이전의 연산 결과를 내버려두고 다른 연산을 수행하는 역할을 합니다. 이전 연산과 별 상관 없는 다른 연산을 할 때 사용할 수 있죠. do notataion은 다음의 1대1 변환을 기준으로 컴파일됩니다. do e1 e2 는 e1 >> e2와 동일합니다. do p <- e1 e2 는 e1 >>= (v -> case v of p -> e2 _ -> fail "s") 와 동일합니다.
  • 27. fail e1 >>= (v -> case v of p -> e2 _ -> fail "s" 이 코드를 보면 fail 함수가 쓰이고 있는 걸 알 수 있습니다. 저기서 "s"는 오류 상황에 맞는 어떤 텍스트를 의미합니다. 결국 fail 함수는 do notation 내부에서 어떤 잘못된 결과가 나왔을 때 그에 따른 처리를 하기 위한 함수라고 볼 수 있죠. 그리고 Maybe Monad에서 fail 함수는 다음과 같이 정의되어 있습니다. fail _ = Nothing 따라서 do notation 내부에서 어떤 잘못된 결과가 발생했을 때 fail 함수가 호출이 되고, 이는 Nothing을 리턴하므로 연산 도중 뭔가 실패했을 때 Nothing을 반환하고 끝이 나게 되는 것입니다.
  • 28. List Monad List 역시 Monad 입니다. Applicative Functor에서 말했듯이, List Monad는 비결정성을 의미합니다. List Monad는 다음과 같이 정의되어 있습니다. instance Monad [] where return x = [x] xs >>= f = concat (map f xs) fail _ = [] 리스트 모나드는 바인딩을 할 때(>>=) 주어진 함수를 map의 모든 원소에 적용한 후 그걸 합치는 형태로 동작함을 알 수 있습니다. 그리고 fail 함수가 []를 리턴하니 do notation 내부에서 뭔가 문제가 생겼을 때 []를 리턴하고 끝날 것이라는 것도 알 수 있죠.
  • 29. List Monad List Monad의 사용 예제를 살펴봅시다. Prelude> [3, 4, 5] >>= x -> [x, -x] [3, -3, 4, -4, 5, -5] Prelude> [1,2] >>= n -> ['a','b'] >>= ch -> return (n, ch) [(1,'a'),(1,'b'),(2,'a'),(2,'b')]
  • 30. List Monad do notation 내부에서 let 키워드를 사용할 수 있습니다. 그리고 List Monad의 do notation과 List comprehension은 사실 완전히 동일한 것입니다. listOfTuples = do n <- [1,2] let chs = ['a','b'] ch <- chs return (n, ch) listOfTuples' = [ (n, ch) | n <- [1,2], ch <- ['a','b'] ]
  • 31. Monad laws Monad 역시 Applicative Functor와 마찬가지로 반드시 지켜야하는 규칙이 있습니다. 이 것도 자세한 내용은 생략하지만, 필요할 때 찾아서 깊이 있게 공부해보시는 것을 권장합니다. • Left Identity return a >>= f ≡ f a • Right Identity m >>= return ≡ m • Associativity (m >>= f) >>= g ≡ m >>= (x -> f x >>= g)
  • 32. IO Monad Haskell에서는 IO 작업이 Monad로 취급됩니다. IO Monad는 Side Effect가 발생할 수 있는 연산을 뜻하는 Context입니다. Haskell은 IO Monad를 통해 모든 Side Effect가 발생할 수 있는 연산과 그렇지 않은 연산을 완전히 분리합니다. Haskell의 main 함수는 IO () 를 리턴합니다. main :: IO () main = do putStrLn "Hello, World!" 모든 IO 연산은 결과 값으로 IO 컨텍스트 내부의 값을 리턴하기 때문에 주로 do notation을 써서 코딩하게 됩니다. 위 코드를 파일에 저장하고 cmd 창에서 ghc (file name).hs 를 실행하면 실행 파일이 생성됩니다. 실행해서 결과를 확인해봅시다.
  • 33. IO Monad 간단하게 값을 입력 받아서 그대로 echo 해주고 종료하는 프로그램을 만들어 봅시다. main = do str <- getLine putStrLn str getLine 함수는 IO String 타입을 갖고 있습니다. 이 함수는 외부에서 값을 입력받아 그걸 IO Context로 감싸서 결과를 돌려줍니다. side effect를 갖고 있는 IO 함수이기 때문이죠. putStrLn 역시 화면에 값을 출력하는 side effect를 갖고 있는 IO 함수기 때문에 IO () 타입을 가집니다. IO와 관련해서도 굉장히 다양한 함수들이 있습니다. 역시 Hoogle 등에서 System.IO 모듈의 함수를 한 번 살펴보시는 걸 권장합니다.