Domain Driven Design with the F# type System -- F#unctional Londoners 2014Scott Wlaschin
(Video of these slides here http://fsharpforfunandprofit.com/ddd)
Statically typed functional programming languages like F# encourage a very different way of thinking about types. The type system is your friend, not an annoyance, and can be used in many ways that might not be familiar to OO programmers.
Types can be used to represent the domain in a fine-grained, self documenting way. And in many cases, types can even be used to encode business rules so that you literally cannot create incorrect code. You can then use the static type checking almost as an instant unit test — making sure that your code is correct at compile time.
In this talk, we'll look at some of the ways you can use types as part of a domain driven design process, with some simple real world examples in F#. No jargon, no maths, and no prior F# experience necessary.
Code, links to video, etc., at http://fsharpforfunandprofit.com/ddd
NEW AND IMPROVED - added sections on:
* why OO, not FP is scary
* designing with states and transitions
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Scott Wlaschin
(Video of these slides here http://fsharpforfunandprofit.com/ddd)
Statically typed functional programming languages like F# encourage a very different way of thinking about types. The type system is your friend, not an annoyance, and can be used in many ways that might not be familiar to OO programmers.
Types can be used to represent the domain in a fine-grained, self documenting way. And in many cases, types can even be used to encode business rules so that you literally cannot create incorrect code. You can then use the static type checking almost as an instant unit test — making sure that your code is correct at compile time.
In this talk, we'll look at some of the ways you can use types as part of a domain driven design process, with some simple real world examples in F#. No jargon, no maths, and no prior F# experience necessary.
Code, links to video, etc., at http://fsharpforfunandprofit.com/ddd
NEW AND IMPROVED - added sections on:
* why OO, not FP is scary
* designing with states and transitions
1. Null was used as an exception to point out issues.
2. Null used three sentences to summarize the key details.
3. Null's summary highlighted the object, option, exception handling, and Kotlin programming language.
23. たのしい高階関数 λ
高階関数ってなに?
def twice(f:(Int => Int))(x:Int):Int = f(f(x))
関数 twice は
Int 型の引数を受け取り Int 型の値を返す関数 f
を受け取り、
Int 型の引数を受け取り Int 型の値を返す関数
を返す関数
24. たのしい高階関数 λ
高階関数ってなに?
def twice(f:(Int => Int))(x:Int):Int = f(f(x))
def add1(x:Int) = x + 1
> val add2 = twice(add1)(_)
add2: Int => Int = <function1>
> add2(3)
res1: Int = 5
25. たのしい高階関数 λ
高階関数ってなに?
def twice(f:(Int => Int))(x:Int):Int = f(f(x))
def add1(x:Int) = x + 1
Int 型の引数を受け取り
Int 型の値を返す関数
> val add2 = twice(add1)(_)
add2: Int => Int = <function1>
Int 型の引数を受け取り
> add2(3) Int 型の値を返す関数
res1: Int = 5
26. たのしい高階関数 λ
高階関数ってなに?
def twice(f:(Int => Int))(x:Int):Int = f(f(x))
def add1(x:Int) = x + 1
> val add2 = twice(add1)(_)
add2: Int => Int = <function1>
> add2(3) = twice(add1)(3) = add1(add1(3))
res1: Int = 5
38. たのしい高階関数 λ
高階関数を学ぶメリット
list.map(new Func1<Integer, Integer>() {
public Integer apply(Integer a) { return a * 2;}
}).filter(new Func1<Integer, Boolean>() {
public Boolean apply(Integer a) { return a >= 10;}
}).reduce(new Func2<Integer, Integer, Integer>() {
public Integer apply(Integer a, Integer b) { return a + b; }
});
54. たのしい高階関数 λ
リストを扱う高階関数
map 関数の実装
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
ヘッダ テイル
55. たのしい高階関数 λ
リストを扱う高階関数
map 関数の実装
def map[B, That](f: A => B)
(implicit bf: CanBuildFrom[Repr, B, That])
: That = {
val b = bf(repr)
b.sizeHint(this)
for (x <- this) b += f(x)
b.result
}
56. たのしい高階関数 λ
リストを扱う高階関数
map 関数の実装(簡略化)
def map[B, That](f: A => B)
def map[A, B](f: A => Bbf:List[B] = {
(implicit ): CanBuildFrom[Repr, B, That])
val b = new :ListBuffer[B]()
That = {
val b = bf(repr)
b.sizeHint(this)
b.sizeHint(this) buff += f(x)
for (x <- this)
for (x <- this) b += f(x)
b.result
}b.result
}
64. たのしい高階関数 λ
リストを扱う高階関数
foldl / foldr 関数のイメージ
foldl f 0 [1,2,3,4] foldr f 0 [1,2,3,4]
f f
f 4 1 f
f 3 2 f
f 2 3 f
0 1 4 0
関数 f でリストを畳み込んで単一の値を返す。
左からと右からの畳み込み関数がある。
67. たのしい高階関数 λ
リストを扱う高階関数
foldl / foldr 関数の例
> let add x y = x + y
> foldl add 0 [1,2,3,4]
10
> foldr add 0 [1,2,3,4]
10
68. たのしい高階関数 λ
リストを扱う高階関数
foldl / foldr 関数の例
> let add x y = x + y
> foldl add 0 [1,2,3,4]
= add(add(add(add(0, 1), 2), 3), 4)
= add(add(add(1, 2), 3), 4)
= add(add(3, 3), 4)
= add(6, 4)
=10
> foldr add 0 [1,2,3,4]
10
69. たのしい高階関数 λ
リストを扱う高階関数
foldl / foldr 関数の例
> let add x y = x + y
> foldl add 0 [1,2,3,4]
10
> foldr add 0 [1,2,3,4]
= add(1, add(2, add(3, add(4, 0))))
= add(1, add(2, add(3, 4)))
= add(1, add(2, 7))
= add(1, 9)
= 10
70. たのしい高階関数 λ
リストを扱う高階関数
foldr 関数の実装
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
71. たのしい高階関数 λ
リストを扱う高階関数
foldr 関数の実装
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
foldr k z [] = z
foldr k z (y:ys) = k y (foldr k z ys)
72. たのしい高階関数 λ
リストを扱う高階関数
foldl 関数の実装
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f z0 xs0 = lgo z0 xs0
where
lgo z [] = z
lgo z (x:xs) = lgo (f z x) xs
73. たのしい高階関数 λ
リストを扱う高階関数
foldl 関数の実装
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f z0 xs0 = lgo z0 xs0
where
lgo z [] = z
lgo z (x:xs) = lgo (f z x) xs
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
74. たのしい高階関数 λ
リストを扱う高階関数
foldLeft 関数の実装 (Scala)
def foldLeft[B](z: B)(f: (B, A) => B): B = {
var acc = z
var these = this
while (!these.isEmpty) {
acc = f(acc, these.head)
these = these.tail
}
acc
}
75. たのしい高階関数 λ
リストを扱う高階関数
foldRight 関数の実装 (Scala)
def foldRight[B](z: B)(f: (A, B) => B): B =
if (this.isEmpty) z
else f(head, tail.foldRight(z)(f))
76. たのしい高階関数 λ
リストを扱う高階関数
Scala の foldRight 関数の注意点
scala> (1 to 10000).toList.foldLeft(0)(_ + _)
res0: Int = 50005000
scala> (1 to 10000).toList.foldRight(0)(_ + _)
java.lang.StackOverflowError
77. たのしい高階関数 λ
リストを扱う高階関数
Range の場合は大丈夫
scala> (1 to 10000).foldLeft(0)(_ + _)
res0: Int = 50005000
scala> (1 to 10000).foldRight(0)(_ + _)
res1: Int = 50005000
78. たのしい高階関数 λ
リストを扱う高階関数
Range の foldRight 関数の実装
def foldRight[B](z: B)(op: (A, B) => B): B =
reversed.foldLeft(z)((x, y) => op(y, x))
まさかの reversed !
Reversed は List 型を返すので、
List の foldLeft が使われる