SlideShare a Scribd company logo
Haskell
Study
8. Functor
Context
Haskell의 타입 생성자는 일종의 문맥(Context)과 같이 취급할 수 있습니다. 예를 들어 Maybe 타입
생성자는 Maybe 라는 문맥과 그 문맥 속의 타입(Int, Char 등)으로 생각할 수 있죠.
Maybe
Int
Maybe Int에서 Maybe는 해당 타입에 대한 Context입니다. Maybe는 불확실성- 즉, 결과가
존재할 수도(Just Int) 그렇지 않을수도(Nothing)있다라는 부가적인 문맥 정보를 가집니다.
타입 생성자를 이런 문맥의 관점에서 봤을 때 특정 타입 생성자에 대한 타입 클래스는 그 문맥 고유의
행동을 정의하는 것으로 생각할 수 있습니다.
Functor
Functor 타입 클래스는 context에 대해 함수를 적용할 수 있는 타입들의 집합입니다. Functor 타입
클래스는 다음 하나의 함수 인터페이스만을 갖고 있습니다.
class Functor f where
	fmap :: ( a -> b ) -> f a -> f b
Functor는 a -> b 함수를 하나 받아서, context f 내의 있는 a 타입의 원소에 그 함수를 적용시킨
결과 f b 를 만들어내는 함수 fmap을 쓸 수 있는 타입들의 집합입니다. list 역시 일종의 context로 볼
수 있고(타입 생성자이므로), 이 때 list에 대한 fmap은 우리가 계속 써왔던 map입니다.
map :: ( a -> b ) -> [a] -> [b]
list context에 대한 fmap은 해당 list 내부에 속한 원소 전체에 대해 해당 함수를 적용시키는 것이죠.
Functor
Maybe 타입에 대한 Functor는 다음과 같이 정의됩니다.
instance Functor Maybe where
	 fmap _ Nothing = Nothing
	 fmap f (Just a) = Just (f a)
Maybe 타입은 Context 측면에서 봤을 때 불확실성(존재하는지 아닌지 - 성공했는지 실패했는지
알 수 없음)을 의미하기 때문에, 그 내부에 어떤 값도 없다면(Nothing) 결과로 Nothing을 반환하고,
그렇지 않다면 Context 내부에 속한 값(Just a에서 a)에 함수를 적용한 결과를 반환합니다.
Functor
Functor는 임의 Context에 대해 동작하는 함수를 만들고 싶을 때 유용합니다.
threeRepeat :: (Functor f) => f a -> f [a]
threeRepeat = fmap (replicate 3)
위와 같은 함수가 있다고 합시다. 이 함수는 인자로 넘어오는 값이 어떤 Context에 속해있느냐에 따라
다른 동작을 하게 됩니다. Context와 무관하게 유연한 동작을 할 수 있는 거죠.
Prelude> threeRepeat [1,2,3,4]
[[1,1,1],[2,2,2],[3,3,3],[4,4,4]]
Prelude> threeRepeat (Just 3)
Just [3,3,3]
Functor Rule
Functor 타입 클래스에 속하는 타입들은 반드시 다음 규칙을 만족해야합니다.
1. fmap id = id
id는 인자로 넘긴 값을 그냥 그대로 돌려주는 함수입니다(id x = x). fmap id는 Context 내부에
속하는 값에 대해 id 함수를 적용한다는 의미이므로, 그냥 원래 값을 그대로 돌려주는 id와 값의
차이가 없어야할 것입니다.
2. fmap (f . g) = fmap f . fmap g
이는 Context에 대해 합성함수 f . g를 적용한 것과, g, f를 순서대로 Context 내부에 mapping했을
때 결과의 차이가 없어야함을 뜻합니다.
Functor Rule
앞의 규칙은 Haskell 컴파일러가 알아서 잡아주지 않기 때문에, Functor 타입 클래스에 속하는
타입을 만들 때 스스로 주의해서 작성해야합니다.
저런 규칙은 얼핏 불필요하고 번거로워보일 수 있지만, 해당 타입을 쓰는 입장에서 fmap의 동작이
어떻게 될지 예측할 수 있게 해주며, fmap 함수가 정말로 Context 내부에 함수를 mapping해준다는
동작 그 자체만을 수행함을 보장해줍니다. 사용자 입장에서 fmap을 쓸 때 다른 부가적인 어떤 결과가
절대 발생하지 않을 것임을 믿고 쓸 수 있다는 뜻이죠.
연습문제
아래 자료구조 Tree에 대한 Functor instance를 작성해봅시다.
data Tree a = Node a [Tree a]
소스 코드 파일은 아마 아래와 같은 형태가 되겠죠.
import Control.Functor
data Tree a = Node a [Tree a]
instance Functor Tree where
	 fmap ...
Applicative Functor
앞에서 Functor는 어떤 일반적인 값에 대한 함수 (a->b)와 Context 속에 속하는 값(f a)이 주어졌을
때 그 Context 내부 값에 함수를 적용시킨 결과 (f b)를 돌려줄 수 있는 타입들의 집합이라고
했습니다.
Applicative Functor는 여기서 한발짝 더 나아간 개념입니다. Haskell의 커링 개념을 이용해서 다음
식을 실행했을 때 결과는 어떻게 될까요?
fmap (*) (Just 3)
이 결과는 당연히 Just (*3)이 될 것입니다. 이건 Context 속에 함수가 들어가 있는 형태로 볼
수 있죠. 이 때 Just (*3)과 Just 6이 있을 때 결과를 계산할 수 있을까요? 왠지 결과로 Just 18
을 얻을 수 있어야할 것 같지 않나요? 이럴 때 쓸 수 있는 타입이 Applicative Functor에 속하는
타입들입니다.
Applicative Functor
Applicative Functor는 다음과 같이 정의되어 있습니다.
class (Functor f) => Applicative f where
	pure :: a -> f a
	(<*>) :: f (a -> b) -> f a -> f b
Applicative 타입 클래스에 속하려면 우선 Functor 타입 클래스에 속해야합니다. Applicative가 한
발 더 나아간 개념이기 때문에 어찌보면 당연한 일이죠.
우선 pure 함수부터 살펴봅시다. pure 함수는 그냥 값이 주어져있을 때 이 값을 단순히 해당
Context 내부로 집어넣는 역할을 합니다. Maybe context에 대해 pure 3 = Just 3 이 될거라고
생각할 수 있겠죠.
Applicative Functor는 사용하려면 Control.Applicative 모듈을 임포트해야합니다
(import Control.Applicative).
Applicative Functor
다음은 Applicative Functor의 핵심 기능을 하는 함수인 <*> 입니다. 이 함수는 Context 내부에
있는 함수를 꺼내서, 그 함수를 Context 내부의 값에 적용시킨 결과를 반환합니다. 예를 들어 Maybe
타입에 대해 Applicative 타입 클래스는 다음과 같이 정의되어 있습니다.
instance Applicative Maybe where
	pure = Just
	 Nothing <*> _ = Nothing
	 (Just f) <*> something = fmap f something
context 속에 어떤 함수도 존재하지 않는다면 Nothing, 그렇지 않다면 그 함수를 Context 속에서
꺼내 fmap을 호출한 결과를 반환하죠.
Applicative Functor
Applicative Functor의 함수 pure와 <*>를 어떻게 쓰는지 예제를 살펴봅시다.
Prelude> Just (+3) <*> Just 9
Just 12
Prelude> pure (+3) <*> Just 10
Just 13
Prelude> Just (++"hahaha") <*> Nothing
Nothing
Prelude> Nothing <*> Just "Test"
Nothing
Applicative Functor
Haskell의 모든 함수가 다 커링이 된다는 특징 덕분에 여러 개의 인자를 가진 함수에 대해서도 <*>
함수를 적용할 수 있습니다. <*> 함수는 left-associative한 함수기 때문에 왼쪽부터 차례대로 결과를
계산하게 되죠.
Prelude> pure (+) <*> Just 3 <*> Just 5
Just 8
Prelude> pure (+) <*> Just 3 <*> Nothing
Nothing
Prelude> pure (+) <*> Nothing <*> Just 5
Nothing
Applicative Functor
Applicative Functor가 지켜야하는 규칙(Functor가 지켜야할 규칙과 마찬가지로 Applicative
Functor 역시 만족해야하는 규칙이 있습니다. 이후 설명)에 의해, pure f <*> x 는 fmap f x와 항상
동일합니다. 그리고 이 특징을 이용해 Applicative Functor를 좀 더 가독성 있는 방식으로 사용할 수
있습니다.
(<$>) :: (Functor f) => (a -> b) -> f a -> f b
f <$> x = fmap f x
<$>는 단순히 fmap을 중위 연산자의 형태로 표현한 함수입니다. 이 함수를 이용하면 pure f <*>
x <*> y <*> ... 형태의 식을 f <$> x <*> y <*> ... 형태로 바꿔쓸 수 있고, 이는 중간의
<$>, <*>를 제외하고 보면 일반적인 함수를 그냥 쓰는 것과 완전히 동일해 보입니다.
Applicative Functor
List 역시 Applicative Functor입니다. Applicative Functor로서의 List는 비결정성이라는
Context를 가지게 됩니다.
instance Applicative [] where
	 pure x = [x]
	 fs <*> xs = [f x | f <- fs, x <- xs]
함수 list와 원소 list에 대해, 모든 종류의 함수 적용 조합을 다 수행한 결과를 리스트에 담고 있죠. 이는
어떤 함수를 어떤 원소에 대해 적용할지 모르는, 비결정적인 연산의 결과를 의미합니다.
Applicative Functor
여러 가지 예제를 살펴봅시다.
Prelude> [(*0),(+100),(^2)] <*> [1, 2, 3]
[0, 0, 0, 101, 102, 103, 1, 4, 9]
Prelude> [(+), (*)] <*> [1, 2] <*> [3,4]
[4, 5, 5, 6, 3, 4, 6, 8]
Prelude> (++) <$> ["ha","heh","hmm"] <*> ["?","!","."]
["ha?", "ha!", "ha.", "heh?", "heh!", "heh.", "hmm?", "hmm!", "hmm."]
Prelude> (++) <$> (Just "ha") <*> (Just "!")
Just "ha!"
Applicative Functor는 위와 같이 이미 어떤 Context 내에 들어가 있는 값들에 대해 함수를
호출하고 싶을 때 유용하게 사용할 수 있습니다.
Applicative Functor
앞에서 언급했듯 Applicative Functor 역시 Functor와 마찬가지로 반드시 지켜야하는 규칙이
있습니다. 다 설명하자면 내용이 복잡하고 기니 설명은 생략하고, 규칙만 소개하겠습니다. 이후
Applicative Functor를 구현해야할 일이 생긴다면 그 때 깊이 있게 공부해보시는게 좋을 것 같네요.
1. pure id <*> v = v
2. pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
3. pure f <*> pure x = pure (f x)
4. u <*> pure y = pure ($ y) <*> u

More Related Content

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

What's hot (20)

PDF
Ad hoc Polymorphism using Type Classes and Cats
PDF
Haskell study 12
PDF
Sequence and Traverse - Part 1
PDF
The lazy programmer's guide to writing thousands of tests
PPTX
Taking your side effects aside
PDF
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
PDF
Monoids - Part 1 - with examples using Scalaz and Cats
PPTX
C++20 features
PDF
Haskell study 14
PDF
ZIO-Direct - Functional Scala 2022
PDF
Functor, Apply, Applicative And Monad
PDF
Functional Patterns in Domain Modeling
PDF
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
PDF
Applicative Functor
PDF
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
PDF
Left and Right Folds - Comparison of a mathematical definition and a programm...
PDF
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
PDF
Functional Programming 101 with Scala and ZIO @FunctionalWorld
PDF
Introdução a Banco de Dados (Parte 3)
PPTX
SQL(DDL,DML,DCL,TCL)
Ad hoc Polymorphism using Type Classes and Cats
Haskell study 12
Sequence and Traverse - Part 1
The lazy programmer's guide to writing thousands of tests
Taking your side effects aside
Nat, List and Option Monoids - from scratch - Combining and Folding - an example
Monoids - Part 1 - with examples using Scalaz and Cats
C++20 features
Haskell study 14
ZIO-Direct - Functional Scala 2022
Functor, Apply, Applicative And Monad
Functional Patterns in Domain Modeling
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Applicative Functor
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
Left and Right Folds - Comparison of a mathematical definition and a programm...
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Introdução a Banco de Dados (Parte 3)
SQL(DDL,DML,DCL,TCL)
Ad

Viewers also liked (12)

PDF
하스켈 모나드
PPTX
El Protocolo de Kioto
PPS
Fotos graciosas 33657
PPTX
Learn Haskell The Easy Way
PDF
Functional Programming by Examples using Haskell
PDF
Haskell in the Real World
PDF
[IGC] 엔씨소프트 이경종 - 강화 학습을 이용한 NPC AI 구현
PDF
Functional programming with haskell
PDF
버전관리를 들어본적 없는 사람들을 위한 DVCS - Git
PDF
[NDC 2010] 그럴듯한 랜덤 생성 컨텐츠 만들기
PDF
Real World Haskell: Lecture 1
PDF
[NDC 2009] 행동 트리로 구현하는 인공지능
하스켈 모나드
El Protocolo de Kioto
Fotos graciosas 33657
Learn Haskell The Easy Way
Functional Programming by Examples using Haskell
Haskell in the Real World
[IGC] 엔씨소프트 이경종 - 강화 학습을 이용한 NPC AI 구현
Functional programming with haskell
버전관리를 들어본적 없는 사람들을 위한 DVCS - Git
[NDC 2010] 그럴듯한 랜덤 생성 컨텐츠 만들기
Real World Haskell: Lecture 1
[NDC 2009] 행동 트리로 구현하는 인공지능
Ad

Similar to Haskell study 8 (20)

PPTX
하스켈 프로그래밍 입문 2
PPTX
Valentine
PDF
함수적 사고 2장
PDF
Finding Functional Programming
PDF
Clojure Monad
PPTX
하스켈 프로그래밍 입문
PPTX
9장10장,stl abstract interface
PPTX
STL활용, abstract interface
PPTX
모어 이펙티브 c++ 5장 스터디
PPTX
Abstract syntax semantic analyze
PPTX
종이접기(fold) 프로그래밍
PDF
Pure Function and Honest Design
PDF
Functional Programming
PDF
C++ Advanced 강의 4주차
PDF
Haskell study 0
PPTX
Functional programming
PDF
[Effective Modern C++] Chapter1 - item1
PDF
Pure Function and Rx
PDF
More effective c++ chapter4 이후 항목 29까지
PPTX
Functional programming
하스켈 프로그래밍 입문 2
Valentine
함수적 사고 2장
Finding Functional Programming
Clojure Monad
하스켈 프로그래밍 입문
9장10장,stl abstract interface
STL활용, abstract interface
모어 이펙티브 c++ 5장 스터디
Abstract syntax semantic analyze
종이접기(fold) 프로그래밍
Pure Function and Honest Design
Functional Programming
C++ Advanced 강의 4주차
Haskell study 0
Functional programming
[Effective Modern C++] Chapter1 - item1
Pure Function and Rx
More effective c++ chapter4 이후 항목 29까지
Functional programming

More from Nam Hyeonuk (17)

PPTX
Next 게임 실전 프로젝트 슬라이드
PDF
Haskell study 15
PDF
Haskell study 11
PDF
Haskell study 10
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 10
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 8

  • 2. Context Haskell의 타입 생성자는 일종의 문맥(Context)과 같이 취급할 수 있습니다. 예를 들어 Maybe 타입 생성자는 Maybe 라는 문맥과 그 문맥 속의 타입(Int, Char 등)으로 생각할 수 있죠. Maybe Int Maybe Int에서 Maybe는 해당 타입에 대한 Context입니다. Maybe는 불확실성- 즉, 결과가 존재할 수도(Just Int) 그렇지 않을수도(Nothing)있다라는 부가적인 문맥 정보를 가집니다. 타입 생성자를 이런 문맥의 관점에서 봤을 때 특정 타입 생성자에 대한 타입 클래스는 그 문맥 고유의 행동을 정의하는 것으로 생각할 수 있습니다.
  • 3. Functor Functor 타입 클래스는 context에 대해 함수를 적용할 수 있는 타입들의 집합입니다. Functor 타입 클래스는 다음 하나의 함수 인터페이스만을 갖고 있습니다. class Functor f where fmap :: ( a -> b ) -> f a -> f b Functor는 a -> b 함수를 하나 받아서, context f 내의 있는 a 타입의 원소에 그 함수를 적용시킨 결과 f b 를 만들어내는 함수 fmap을 쓸 수 있는 타입들의 집합입니다. list 역시 일종의 context로 볼 수 있고(타입 생성자이므로), 이 때 list에 대한 fmap은 우리가 계속 써왔던 map입니다. map :: ( a -> b ) -> [a] -> [b] list context에 대한 fmap은 해당 list 내부에 속한 원소 전체에 대해 해당 함수를 적용시키는 것이죠.
  • 4. Functor Maybe 타입에 대한 Functor는 다음과 같이 정의됩니다. instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just a) = Just (f a) Maybe 타입은 Context 측면에서 봤을 때 불확실성(존재하는지 아닌지 - 성공했는지 실패했는지 알 수 없음)을 의미하기 때문에, 그 내부에 어떤 값도 없다면(Nothing) 결과로 Nothing을 반환하고, 그렇지 않다면 Context 내부에 속한 값(Just a에서 a)에 함수를 적용한 결과를 반환합니다.
  • 5. Functor Functor는 임의 Context에 대해 동작하는 함수를 만들고 싶을 때 유용합니다. threeRepeat :: (Functor f) => f a -> f [a] threeRepeat = fmap (replicate 3) 위와 같은 함수가 있다고 합시다. 이 함수는 인자로 넘어오는 값이 어떤 Context에 속해있느냐에 따라 다른 동작을 하게 됩니다. Context와 무관하게 유연한 동작을 할 수 있는 거죠. Prelude> threeRepeat [1,2,3,4] [[1,1,1],[2,2,2],[3,3,3],[4,4,4]] Prelude> threeRepeat (Just 3) Just [3,3,3]
  • 6. Functor Rule Functor 타입 클래스에 속하는 타입들은 반드시 다음 규칙을 만족해야합니다. 1. fmap id = id id는 인자로 넘긴 값을 그냥 그대로 돌려주는 함수입니다(id x = x). fmap id는 Context 내부에 속하는 값에 대해 id 함수를 적용한다는 의미이므로, 그냥 원래 값을 그대로 돌려주는 id와 값의 차이가 없어야할 것입니다. 2. fmap (f . g) = fmap f . fmap g 이는 Context에 대해 합성함수 f . g를 적용한 것과, g, f를 순서대로 Context 내부에 mapping했을 때 결과의 차이가 없어야함을 뜻합니다.
  • 7. Functor Rule 앞의 규칙은 Haskell 컴파일러가 알아서 잡아주지 않기 때문에, Functor 타입 클래스에 속하는 타입을 만들 때 스스로 주의해서 작성해야합니다. 저런 규칙은 얼핏 불필요하고 번거로워보일 수 있지만, 해당 타입을 쓰는 입장에서 fmap의 동작이 어떻게 될지 예측할 수 있게 해주며, fmap 함수가 정말로 Context 내부에 함수를 mapping해준다는 동작 그 자체만을 수행함을 보장해줍니다. 사용자 입장에서 fmap을 쓸 때 다른 부가적인 어떤 결과가 절대 발생하지 않을 것임을 믿고 쓸 수 있다는 뜻이죠.
  • 8. 연습문제 아래 자료구조 Tree에 대한 Functor instance를 작성해봅시다. data Tree a = Node a [Tree a] 소스 코드 파일은 아마 아래와 같은 형태가 되겠죠. import Control.Functor data Tree a = Node a [Tree a] instance Functor Tree where fmap ...
  • 9. Applicative Functor 앞에서 Functor는 어떤 일반적인 값에 대한 함수 (a->b)와 Context 속에 속하는 값(f a)이 주어졌을 때 그 Context 내부 값에 함수를 적용시킨 결과 (f b)를 돌려줄 수 있는 타입들의 집합이라고 했습니다. Applicative Functor는 여기서 한발짝 더 나아간 개념입니다. Haskell의 커링 개념을 이용해서 다음 식을 실행했을 때 결과는 어떻게 될까요? fmap (*) (Just 3) 이 결과는 당연히 Just (*3)이 될 것입니다. 이건 Context 속에 함수가 들어가 있는 형태로 볼 수 있죠. 이 때 Just (*3)과 Just 6이 있을 때 결과를 계산할 수 있을까요? 왠지 결과로 Just 18 을 얻을 수 있어야할 것 같지 않나요? 이럴 때 쓸 수 있는 타입이 Applicative Functor에 속하는 타입들입니다.
  • 10. Applicative Functor Applicative Functor는 다음과 같이 정의되어 있습니다. class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b Applicative 타입 클래스에 속하려면 우선 Functor 타입 클래스에 속해야합니다. Applicative가 한 발 더 나아간 개념이기 때문에 어찌보면 당연한 일이죠. 우선 pure 함수부터 살펴봅시다. pure 함수는 그냥 값이 주어져있을 때 이 값을 단순히 해당 Context 내부로 집어넣는 역할을 합니다. Maybe context에 대해 pure 3 = Just 3 이 될거라고 생각할 수 있겠죠. Applicative Functor는 사용하려면 Control.Applicative 모듈을 임포트해야합니다 (import Control.Applicative).
  • 11. Applicative Functor 다음은 Applicative Functor의 핵심 기능을 하는 함수인 <*> 입니다. 이 함수는 Context 내부에 있는 함수를 꺼내서, 그 함수를 Context 내부의 값에 적용시킨 결과를 반환합니다. 예를 들어 Maybe 타입에 대해 Applicative 타입 클래스는 다음과 같이 정의되어 있습니다. instance Applicative Maybe where pure = Just Nothing <*> _ = Nothing (Just f) <*> something = fmap f something context 속에 어떤 함수도 존재하지 않는다면 Nothing, 그렇지 않다면 그 함수를 Context 속에서 꺼내 fmap을 호출한 결과를 반환하죠.
  • 12. Applicative Functor Applicative Functor의 함수 pure와 <*>를 어떻게 쓰는지 예제를 살펴봅시다. Prelude> Just (+3) <*> Just 9 Just 12 Prelude> pure (+3) <*> Just 10 Just 13 Prelude> Just (++"hahaha") <*> Nothing Nothing Prelude> Nothing <*> Just "Test" Nothing
  • 13. Applicative Functor Haskell의 모든 함수가 다 커링이 된다는 특징 덕분에 여러 개의 인자를 가진 함수에 대해서도 <*> 함수를 적용할 수 있습니다. <*> 함수는 left-associative한 함수기 때문에 왼쪽부터 차례대로 결과를 계산하게 되죠. Prelude> pure (+) <*> Just 3 <*> Just 5 Just 8 Prelude> pure (+) <*> Just 3 <*> Nothing Nothing Prelude> pure (+) <*> Nothing <*> Just 5 Nothing
  • 14. Applicative Functor Applicative Functor가 지켜야하는 규칙(Functor가 지켜야할 규칙과 마찬가지로 Applicative Functor 역시 만족해야하는 규칙이 있습니다. 이후 설명)에 의해, pure f <*> x 는 fmap f x와 항상 동일합니다. 그리고 이 특징을 이용해 Applicative Functor를 좀 더 가독성 있는 방식으로 사용할 수 있습니다. (<$>) :: (Functor f) => (a -> b) -> f a -> f b f <$> x = fmap f x <$>는 단순히 fmap을 중위 연산자의 형태로 표현한 함수입니다. 이 함수를 이용하면 pure f <*> x <*> y <*> ... 형태의 식을 f <$> x <*> y <*> ... 형태로 바꿔쓸 수 있고, 이는 중간의 <$>, <*>를 제외하고 보면 일반적인 함수를 그냥 쓰는 것과 완전히 동일해 보입니다.
  • 15. Applicative Functor List 역시 Applicative Functor입니다. Applicative Functor로서의 List는 비결정성이라는 Context를 가지게 됩니다. instance Applicative [] where pure x = [x] fs <*> xs = [f x | f <- fs, x <- xs] 함수 list와 원소 list에 대해, 모든 종류의 함수 적용 조합을 다 수행한 결과를 리스트에 담고 있죠. 이는 어떤 함수를 어떤 원소에 대해 적용할지 모르는, 비결정적인 연산의 결과를 의미합니다.
  • 16. Applicative Functor 여러 가지 예제를 살펴봅시다. Prelude> [(*0),(+100),(^2)] <*> [1, 2, 3] [0, 0, 0, 101, 102, 103, 1, 4, 9] Prelude> [(+), (*)] <*> [1, 2] <*> [3,4] [4, 5, 5, 6, 3, 4, 6, 8] Prelude> (++) <$> ["ha","heh","hmm"] <*> ["?","!","."] ["ha?", "ha!", "ha.", "heh?", "heh!", "heh.", "hmm?", "hmm!", "hmm."] Prelude> (++) <$> (Just "ha") <*> (Just "!") Just "ha!" Applicative Functor는 위와 같이 이미 어떤 Context 내에 들어가 있는 값들에 대해 함수를 호출하고 싶을 때 유용하게 사용할 수 있습니다.
  • 17. Applicative Functor 앞에서 언급했듯 Applicative Functor 역시 Functor와 마찬가지로 반드시 지켜야하는 규칙이 있습니다. 다 설명하자면 내용이 복잡하고 기니 설명은 생략하고, 규칙만 소개하겠습니다. 이후 Applicative Functor를 구현해야할 일이 생긴다면 그 때 깊이 있게 공부해보시는게 좋을 것 같네요. 1. pure id <*> v = v 2. pure (.) <*> u <*> v <*> w = u <*> (v <*> w) 3. pure f <*> pure x = pure (f x) 4. u <*> pure y = pure ($ y) <*> u