-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrss.xml
More file actions
707 lines (704 loc) · 118 KB
/
Copy pathrss.xml
File metadata and controls
707 lines (704 loc) · 118 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>Young Gyu's Blog</title>
<link></link>
<description><![CDATA[Young Gyu's blog]]></description>
<atom:link href="/rss.xml" rel="self"
type="application/rss+xml" />
<lastBuildDate>Tue, 07 Feb 2017 22:42:11 UT</lastBuildDate>
<item>
<title>Javascript 함수형 프로그래밍</title>
<link>/posts/2017/02/08/Functional_Programming_for_JavaScript%20.html</link>
<description><![CDATA[<p>많은 분들과 마찬가지로 몇 달 전부터 함수형 프로그래밍에 대해 많은 얘기를 듣기 시작했습니다. 나는 그것이 무엇인지 전혀 알 수 없었습니다. 그냥 나에게는 어떤 전문용어처럼 들뎠습니다. 그 이후로 저는 함수 프로그래밍에 대해서 좀 깊게 탐구했고, 이 모든 것들에 대해 듣고 있는 처음 접하는 사람들을 밝혀주려했지만, 그러나 무엇을 해야할지 잘 몰랐습니다. 함수형 프로그래밍 언어에 관해 이야기 할 때 몇 가지 경향이 있습니다 : Haskell과 Lisp. 두 언어 모두 기능 언어이지만 실제로는 매우 다르고 각 언어는 각각 다른 장단점을 가지고 있습니다. 이 글을 다 읽고 나면, 그것이 무엇을 의미하는지 잘 알게 될것입니다. 둘 다 자손 언어의 그들의 몫을 가지고 있습니다. 여러분이 들어 보셨던 두 가지 언어로는 Elm과 Clojurescript가 있는데, 둘 다 JavaScript로 컴파일됩니다. 그러나 각 언어의 세부 사항을 배우기 전에 실제 목표는 기능 프로그래밍의 핵심 개념과 패턴을 소개하는 것입니다. 나는이 토끼 구멍으로 뛰어 들어가기 전에 적어도 한 잔의 커피를 마시는 것이 좋습니다. 순수 함수 함수 프로그래밍의 핵심은 논리를 기술하는 형식적인 수학입니다 : 람다 미적분학. 수학자들은 프로그램을 첫 번째 개념, 즉 순수 함수로 이끄는 데이터 변환으로 설명합니다. 순수 함수는 부작용이없는 함수입니다. 순수 함수는 함수의 입력에만 의존하며 출력은 동일한 입력에 대해 동일해야합니다. 다음은 그 예입니다.</p>
<p>Like many of you, I started hearing a lot about functional programming several months ago and I had no idea what it was. It was just a buzzword to me. Since then, I’ve explored the depths of functional programming and I thought I’d try to help demystify the newcomer who keeps hearing about all this stuff but doesn’t know what to make of it. When talking about functional programming languages, there tends to be a few flavors: Haskell and Lisp, with plenty of debate over which is better. Although they are both functional languages, they are in fact quite different, each with their own trade-offs. By the end of this article, I hope you have a better idea of what those are. Both have their share of descendant languages as well. Two such languages that you may have heard of are Elm and Clojurescript, both of which compile into JavaScript. But before I get into the specifics of each language, my real goal is to instill in you some of the core concepts and patterns behind functional programming. I highly recommend having at least one cup of coffee on hand before diving into this rabbit hole. Pure Functions At the heart of functional programming is the formal mathematics of describing logic: lambda calculus. Mathematicians like to describe programs as transformations of data which leads to the first concept — pure functions. Pure functions are functions without side-effects. Pure functions depend only on the inputs of the function, and the output should be the exact same for the same input. Here’s an example: // pure function const add10 = (a) => a + 10 // impure function due to external non-constants let x = 10 const addx = (a) => a + x // also impure due to side-effect const setx = (v) => x = v The impure function indirectly depends on x. If you were to change x, then addx would output a different value for the same inputs. This makes it hard to statically analyze and optimize programs at compile-time. But more pragmatically for JavaScript developers, pure functions bound the congnitive load of programming. When you’re writing a pure function, you only need to concern yourself with the body of the function. You don’t need to worry about externalities that could cause problems, like anything that could change x while when you’re writing the addx function. Function Composition One nice thing about pure functions is that you can compose them into new functions. One special operator used to describe programs in lambda calculus is compose. Compose takes two functions and “composes” them into a new function. Check it out: const add1 = (a) => a + 1 const times2 = (a) => a * 2 const compose = (a, b) => (c) => a(b(c)) const add1OfTimes2 = compose(add1, times2) add1OfTimes2(5) // => 11 The compose is analogous to the preposition “of”. Notice the order of the arguments and how they’re evaluated: add one of times two — the second function is evaluated first. Compose is the opposite of perhaps a more intuitive function you might be familiar with from unix called pipe, which accepts an array of functions. const pipe = (fns) => (x) => fns.reduce((v, f) => f(v), x) const times2add1 = pipe([times2, add1]) times2add1(5) // => 11 With function composition, we can now build more complicated data transformations by joining together (composing) smaller functions. This article does a great job of showing you how function composition can help you process data in a clean and concise way. Pragmatically speaking, composition is a better alternative to object oriented inheritance. Here’s a contrived, but real-world example for you. Suppose you need to create a greeting for your users. const greeting = (name) => <code>Hello ${name}</code> Great! A simple, pure function. Then, your project manager says you now have some more data about your users and wants you to add prefixes to the names. So you go ahead and write this code: const greeting = (name, male=false, female=false) => <code>Hello ${male ? ‘Mr. ‘ : female ? ‘Ms. ‘ : ‘’} ${name}</code> This code isn’t terrible, but what if we start adding more and more booleans for other categories such as “Dr.” or “Sir”? What if we add suffixes as well such as “MD” or “PhD”? And what if we want to have a casual greeting that says “Sup” instead of “Hello”? Well now things have really gotten out of hand. Adding booleans like this to a function isn’t exactly object oriented inheritance, but its a similar situation to when objects have properties and methods that get extended and overridden as they inherit. So as opposed to adding boolean options, lets try to use function composition: const formalGreeting = (name) => <code>Hello ${name}</code> const casualGreeting = (name) => <code>Sup ${name}</code> const male = (name) => <code>Mr. ${name}</code> const female = (name) => <code>Mrs. ${name}</code> const doctor = (name) => <code>Dr. ${name}</code> const phd = (name) => <code>${name} PhD</code> const md = (name) => <code>${name} M.D.</code> formalGreeting(male(phd(“Chet”))) // => “Hello Mr. Chet PhD” This is much more manageable and easier to reason about. Each function does a one simple thing and we’re able to compose them together easily. Now, we haven’t handled all the cases here, and for that we can use our handy pipe function! const identity = (x) => x const greet = (name, options) => { return pipe([ // greeting options.formal ? formalGreeting : casualGreeting, // prefix options.doctor ? doctor : options.male ? male : options.female ? female : identity, // suffix options.phd ? phd : options.md ?md : identity ])(name) } Another benefit of using pure functions and function composition is its much easier to trace errors. Whenever you get an error, you should be able to see a stack trace through every function down to the source of the bug. In object oriented programming, its often quite confusing because you don’t always know the state of the rest of the object which led to the bug. Function Currying Function currying was invented by the same guy who invented Haskell — his name: Haskell Curry (correction: named after Haskell Curry). Function currying is when you call a function with fewer arguments than it wants and that function returns another function to accept the rest of the arguments. This is a good article that explains it in more detail, but here’s a simple example using the Ramda.js curry function. In the example below, we create a curried function “add”, which takes in two arguments. When we pass one argument, we get back a partially applied function we call “add1” which only takes one argument. const add = R.curry((a, b) => a + b) add(1, 2) // => 3 const add1 = add(1) add1(2) // => 3 add1(10) // => 11 In Haskell, all functions are automatically curried. There are no optional or default arguments. Pragmatically, function currying is really convenient when using functions with map, compose and pipe. For example: const users = [{name: ‘chet’, age:25}, {name:‘joe’, age:24}] R.pipe( R.sortBy(R.prop(‘age’)), // sort user by the age property R.map(R.prop(‘name’)), // get each name property R.join(‘,’), // join the names with a comma )(users) // => “joe, chet” This makes data processing feel very declarative. Notice how the code reads just like the comments! Monads, Functors, and Fancy Words Monads and functors are just fancy words for things you already know. If you want to get a firm understanding, I’d highly suggest reading this article which does a great job of explaining with awesome graphics. But this stuff really isn’t all that complicated. Monads are pretty interesting though. Monads can be thought of as a container for a value, and to open up the container and do something to the value, you need to map over it. Here’s a simple example: // monad list = [-1,0,1] list.map(inc) // => [0,1,2] list.map(isZero) // => [false, true, false] The important thing about monads and functors is that mathematicians have been researching these ideas in category theory. This provides us not only a framework for understanding programs, but algebraic theorems and proofs we can use to statically analyze and optimize our code when it’s compiled. This is one of the main benefits of Haskell — the Glasgow Haskell Compiler is a feat of human ingenuity. There are all kinds of theorems and identities expressed in category theory. For example, here’s a simple identity: list.map(inc).map(isZero) // => [true, false, false] list.map(compose(isZero, inc)) // => [true, false, false] When map is compiled, it uses an efficient while loop. In general this is a O(n) operation (linear time), but there is still overhead associated with incrementing the pointer to the next item in the list. So the second version is actually twice as performant. These are the kind of transformations that Haskell does to your code at compile-time to make it blazingly fast — and there’s a really cool trick to doing this that I’ll explain later. To expand on monads just a little, there’s a very interesting monad called the Maybe monad (sometimes called Option or Optional in Swift). In Haskell, theres no such thing as null or undefined. To express something as being potentially null, you need to wrap it in a monad so the Haskell compiler knows what to do with it. The Maybe monad is a union type that’s either Nothing or Just something. In Haskell you’d define a Maybe like this: type Maybe = Nothing | Just x The lowercase x just means any other type. Being a monad, you can .map() over a Maybe to change the value it contains! When you map over a Maybe, if it of type Just, then we apply the function to the value and returns a new Just with that new value. If a the Maybe is of type Nothing, then we return Nothing. In Haskell, the syntax is quite elegant and uses pattern matching, but in JavaScript you might use a Maybe like this: const x = Maybe.Just(10) const n = x.map(inc) n.isJust() // true n.value() // 11 const x= Maybe.Nothing const n = x.map(inc) // no error! n.isNothing // true This monad may not seem terribly useful in your Javascript code, but its interesting to see why it’s so useful in Haskell. Haskell requires you to define what to do in every edge-case of your program, otherwise it won’t compile. When you make an HTTP request, you get back a Maybe type because the request may fail and return nothing. And if you didn’t handle the case in which the request failed, then your program won’t compile. This basically means that it’s impossible to get runtime errors. Maybe your code does the wrong thing, but it doesn’t just magically break like things tend to do in Javascript. This is a big selling point for using Elm. The type system and compiler enforces that your program will run without runtime errors. Thinking about code in the context of monads and algebraic structures will help you define and understand your problem in a structured way. For example, an interesting extention of Maybe is the Railway-Oriented Programming concept for error handling. And observable streams are monads as well for dealing with asynchronous events. There are all kinds of fancy monads and many other words that I don’t myself fully understand. But to keep all the lingo consistent, there are specifications like fantasy-land and the typeclassopedia which try to unify different concepts in category theory for the purpose of writing idiomatic functional code. Referential Transparency and Immutability Another implication of leveraging all this category theory and lambda calculus stuff is referential transparency. Its really hard for mathematicians to analyze logical programs when two things that are the same aren’t equal to each other. This is an issue all over the place in Javascript. {} == {} // false [] == [] // false [1,2] == [1,2] // false Now imagine having to do math in a world without referential transparency. You wouldn’t be able to write proofs that say that an empty array is the same things as an empty array. What should matter is only the value of the array, not the reference pointer to the array. And so functional programming languages resort to using deep-equals to compare values. But this isn’t terribly performant, so there are some neat tricks to make this comparison quicker that leverages references. Before moving on, I just want to make one thing clear: in functional programming, you cannot mutate a variable without changing its reference. Otherwise, the function performing the mutation would be impure! Thus, you can assure that if two variables are referentially equal, their values must be equal as well. And since we can’t mutate variables in-place, then we have to copy those values into a new memory location every time we want to transform it. This is a huge performance loss and results in garbage thrashing. But the solution is using structural sharing (persistent data structures). A simple example of structural sharing is a linked list. Suppose you only keep a reference to the end of the list. When comparing two lists, you can first start by seeing if the ends are referentially equal. This is a nice shortcut because if they are equal, then you’re done — the two lists are the same! Otherwise, you’ll have to start iterating through the items in each list to see if their values are equal. To efficiently add a value to this list, rather than copying entire the list into a new set of memory, you can simply add a link to a new node and keep track of the reference at the new tip. Thus, we’ve structurally shared the previous data structure in a new data structure with a new reference and we’ve persisted the previous data structure as well. The generalized data structure for doing these immutable data transformations is called a hash array mapped trie (HAMT). This is exactly what Immutable.js and Mori.js do. Both Clojurescript and Haskell have this built into the compiler, although I’m not sure it’s implemented in Elm yet. Using immutable data structures can give you performance gains, and help keep your sanity. React assumes props and state are always immutable so it can do an efficient check to see if the previous props and state are referentially equal to the next props and state before unnecessarily re-rendering. And in other circumstance, using immutable data simply helps to ensure that values aren’t changing without you realizing it. Lazy Evaluation Lazy evaluation is sort of a general term that covers more specific concepts like thunks and generators. Lazy evaluation means exactly what you think it does: don’t do something until you absolutely have to, be lazy and procrastinate as long as possible. One analogy is to suppose you have a large, possibly infinite, amount of dishes to wash. Rather than put all the dishes in the sink and wash them at once, let’s be lazy and just take one dish at a time. In Haskell, the true essence lazy evaluation is a little easier to understand, so I’m going to start there. First, we need to understand how programs evaluate. Pretty much every language you’re used to uses innermost reduction. Innermost reduction looks like this: square(3 + 4) square(7) // evaluated the innermost expression 7 * 7 49 This is a sane and reasonable way of evaluating programs. But now, let’s consider outermost reduction: square(3 + 4) (3 + 4) * (3 + 4) // evaluated the outermost expression 7 * (3 + 4) 7 * 7 49 Outermost is clearly less efficient — we’ve had to compute 3 + 4 twice, so the program took 5 steps instead of 4. This is no good. But Haskell keeps a reference to each expression and shares these references as they’re passed down to parent expressions through the outermost reduction. Thus, when 3 + 4 is evaluated the first time, the reference to this expression now points to the expression, 7. Thus we get to skip the duplicate step. square(3 + 4) (3 + 4) * (3 + 4) // evaluated the outermost expression 7 * 7 // both reduced at the same time due to reference sharing 49 Fundamentally, lazy evaluation is outermost evaluation with reference sharing. Haskell does all this stuff under the hood for you, and what that means is you can define things like infinite lists. For example, you can recursively define an infinite list of ones as 1 joined with itself. ones = 1 : ones Suppose you have a function take(n, list) which takes the first n elements of a list. If we used innermost reduction, we’d recursively evaluate list forever, because it’s infinite. But instead, with outermost reduction, we lazily evaluate ones for just as many ones as we need! However, since JavaScript and most other programming languages use innermost reduction, the only way we can replicate these constructs is by treating arrays as functions. For example: const makeOnes = () => {next: () => 1} ones = makeOnes() ones.next() // => 1 ones.next() // => 1 Now we’ve effectively created a lazily evaluated infinite list based on the same recursive definition. Lets create an infinite list of natural numbers: const makeNumbers = () => { let n = 0 return {next: () => { n += 1 return n } } numbers = makeNumbers() numbers.next() // 1 numbers.next() // 2 numbers.next() // 3 In ES2015, there’s actually a standard for this and they’re called function generators. function* numbers() { let n = 0 while(true) { n += 1 yield n } } Laziness can give you huge performance gains. For example, check out Lazy.js operations per second compared to Underscore and Lodash:</p>
<p>Here’s a great example of why that is (given by the Lazy.js website). Suppose you have a huge array of people and you want to perform some transformations on it: const results = _.chain(people) .pluck(‘lastName’) .filter((name) => name.startsWith(‘Smith’)) .take(5) .value() The naïve way of doing this would be to pluck all the lastNames off, filter the entire array, and then take just the first 5. This is what Underscore.js and most other libraries do. But with generators, we can lazily evaluate the expression by going one value at a time until we have 5 last names that start with “Smith”. What’s amazing about Haskell is that this is all baked into the language by using outermost reduction and reference sharing. Every list is inherently lazy. In Javascript, you should probably just use Lazy.js, but if you wanted to create something like this of your own, you just need to understand that each step above returns a new generator. To get values out of a generator, you need to ask for them by calling .next(). The chain method turns the people array into a generator, and each transformation accepts a generator and returns another generator. Then, when you call .value() it simply calls .next() repetitively until there are no more values left. And .take(5) will make sure that you aren’t processing more values than you need to! Now remember that theorem earlier: list.map(inc).map(isZero) // => [false, true, false] list.map(compose(isZero, inc)) // => [false, true, false] Lazy evaluation, inherently does these kind of optimizations for you. Clojure Patterns and Features I’ve talked a lot about Haskell so I want to explain where Clojure fits in to all of this. Clojure has referential transparency, immutable data types, and you cannot mutate variables in-place except for special transactional types called atoms. This is incredibly convenient sometimes when compared to Haskell, where you would be forced to scan values over a stream simply to record values in an associative array to recall elsewhere. Clojure also does not have a strong type system or an insanely powerful compiler like the Glasgow Haskell Compiler. And there is such thing as null in Clojure. That said, functional patterns are strongly encouraged and hard not to use in Clojure. There are two things about Clojure that really stand out to me though: Everything is a primative data type in Clojure, called EDN — the Clojure version of JSON. Rather than having objects and types, everything is just some primitive data structure that’s interpreted however you want. For example, in JavaScript, we have native Date objects. But what happens when you want to serialize a date to JSON? Well you need to create your own custom serializer/deserializer. In Clojure, you might express a date as an associative array with a timestamp and a timezone (unless you’re using the Java implementation). Any string formatting functions just assume the same data structure. So in Clojure, there’s a strong emphasis on data, data transformations, and data processing. Everything is data. The other really cool thing about Clojure is that code is data. Clojure is a Lisp which stands for list processing. The language is just an interpretation of lists where the first item in a list is a function and the rest of the items are arguments — which is why they like to say there’s a Lisp in every language. What’s so cool about Lisps, though, is you can create insanely powerful macros. The macros most people are used to are text substitution macros, where you generate code using some kind of string template. And there’s a cool library for doing this in Javascript called Sweetjs. But in Clojure, since the code itself is just a list, you can inspect the code as a list at compile-time, transform the code, and then evaluate it! This is really convenient for wiring up repetitive boilerplate and allows you to essentially create whatever syntax you want to express something. To do the same thing in JavaScript, you’d need to get very familiar with Babel Plugins and the JavaScript Abstract Syntax Tree (AST) and create your own transpiler. But in Clojure, the AST is just a list! One of the big features of Clojure is the core.async library for handling asynchronous communication, and it has a beautiful way of using macros. In the following example, we create a channel, and the go function is actually a macro. (def echo-chan (chan)) (go (println (<! echo-chan))) (>!! echo-chan “ketchup”) ; prints ketchup What’s amazing here is that go is actually interpretting its argument as a list to generate a bunch of nasty async code that nobody wants to write. It’s looking for <! which is a symbol for essentially subscribing to the channel. Then it generates some code that does the job. Look at all this nasty code that we don’t have to write or deal with: user=> (macroexpand ‘(go (println (<! echo-chan)))) (let* [c__6888<strong>auto</strong> (clojure.core.async/chan 1) captured-bindings__6889__auto__ (clojure.lang.Var/getThreadBindingFrame)] (clojure.core.async.impl.dispatch/run (clojure.core/fn [] (clojure.core/let [f__6890<strong>auto</strong> (clojure.core/fn state-machine__6712__auto__ ([] (clojure.core.async.impl.ioc-macros/aset-all! (java.util.concurrent.atomic.AtomicReferenceArray. 8) 0 state-machine__6712<strong>auto</strong> 1 1)) ([state_8650] (clojure.core/let [old-frame__6713<strong>auto</strong> (clojure.lang.Var/getThreadBindingFrame) ret-value__6714__auto__ (try (clojure.lang.Var/resetThreadBindingFrame (clojure.core.async.impl.ioc-macros/aget-object state_8650 3)) (clojure.core/loop [] (clojure.core/let [result__6715<strong>auto</strong> (clojure.core/case (clojure.core/int (clojure.core.async.impl.ioc-macros/aget-object state_8650 1)) 1 (clojure.core/let [inst_8644 println inst_8645 echo-chan state_8650 (clojure.core.async.impl.ioc-macros/aset-all! state_8650 7 inst_8644)] (clojure.core.async.impl.ioc-macros/take! state_8650 2 inst_8645)) 2 (clojure.core/let [inst_8644 (clojure.core.async.impl.ioc-macros/aget-object state_8650 7) inst_8647 (clojure.core.async.impl.ioc-macros/aget-object state_8650 2) inst_8648 (inst_8644 inst_8647)] (clojure.core.async.impl.ioc-macros/return-chan state_8650 inst_8648)))] (if (clojure.core/identical? result__6715<strong>auto</strong> :recur) (recur) result__6715__auto__))) (catch java.lang.Throwable ex__6716<strong>auto</strong> (clojure.core.async.impl.ioc-macros/aset-all! state_8650 clojure.core.async.impl.ioc-macros/CURRENT-EXCEPTION ex__6716__auto__) (clojure.core.async.impl.ioc-macros/process-exception state_8650) :recur) (finally (clojure.lang.Var/resetThreadBindingFrame old-frame__6713<strong>auto</strong>)))] (if (clojure.core/identical? ret-value__6714__auto__ :recur) (recur state_8650) ret-value__6714<strong>auto</strong>)))) state__6891__auto__ (clojure.core/-> (f__6890<strong>auto</strong>) (clojure.core.async.impl.ioc-macros/aset-all! clojure.core.async.impl.ioc-macros/USER-START-IDX c__6888__auto__ clojure.core.async.impl.ioc-macros/BINDINGS-IDX captured-bindings__6889<strong>auto</strong>))] (clojure.core.async.impl.ioc-macros/run-state-machine-wrapped state__6891__auto__)))) c__6888<strong>auto</strong>) Conclusion That’s basically everything I’ve learned about functional programming in the last few months. I hope that really helps people, especially the JavaScript community, write better code and inevitably create even more awesome things! As for the never-ending debate on Haskell vs Clojure, I think it’s impossible to say which is better because they’re different. Haskell is the the fundamentals of functional programming. Haskell people literally call themselves programming fundamentalists. Haskell is rigid, specific, bulletproof, and ridiculously fast and compact. Clojure is malleable, abstract, and empowering. You can do anything in Clojure because its written on the JVM (and you can do pretty much anything in Java). In Clojure you can build off decades of work in tried and tested Java algorithms. Clojure also has a unique culture of creative programmers behind it with really cool libraries like Overtone and Quill. As far as the Javascript world, I would love to see things moving more into the realm of pure functions. I don’t ever want to see this again. And let’s also get in the habit of only using const types rather than the mutable var or let. Two of my absolute favorite JavaScript libraries are Ramda and Flyd. But Ramda isn’t lazy and doesn’t play nice with Immutable.js. I’d really like to see a library that combines all of these concepts — persistent / shared / immutable data structures with curried, lazily evaluated, composable utility functions. And I’d also like to see libraries using a more consistent language for describing things — the new ES2015 Promises API, for example, uses .then as opposed to .map even though a Promise is totally a monad! This means, that you can’t use Ramda for processing data inside native promises because R.map won’t work. I think the aptly named Fantasyland specification is a grand ideal because it tries to unify the language that all programming data structures speak. If all these libraries like Ramda, Lodash, Lazy.js, Immutable.js, and even the native data primitives like promises use this common language, we can use reuse way more code. You could swap out your native Javascript arrays for Immutable.js lists without having to rewrite all the data processing code you’re using in Ramda or Lazy.js.</p>]]></description>
<pubDate>true</pubDate>
<guid>/posts/2017/02/08/Functional_Programming_for_JavaScript%20.html</guid>
<dc:creator>Young Gyu Park</dc:creator>
</item>
<item>
<title>Solr 클라우드 설치</title>
<link>/posts/2017/02/05/SolrCloud-Setup-Instructions.html</link>
<description><![CDATA[<h2 id="infrastructure">Infrastructure</h2>
<ul>
<li>리눅스 또는 유닉스 3대</li>
<li>ELB 1</li>
<li>각각의 서버에 cl-solr1, cl-solr2, cl-solr3으로 cname을 생성하여 나중에 dns또는 hosts를 통하여 찾을 수 있도록 설정</li>
</ul>
<!--more-->
<h2 id="installations">Installations</h2>
<ol type="1">
<li>zookeeper 설치</li>
<li>Solr 설치</li>
<li>JDK 설치</li>
</ol>
<h2 id="setup">Setup</h2>
<ul>
<li><p>JAVA_HOME 환경 변수 설정</p></li>
<li><p>cl-solr1,cl-solr2,cl-solr3에서 zoo.cfg 파일을 < zookeeper 설치 디렉토리 >/conf 경로 아래에 다음 내용으로 생성</p>
<pre><code>tickTime=2000
dataDir=/var/lib/zookeeper/data
clientPort=2181
initLimit=5
syncLimit=2
server.1=cl-solr1:2888:3888
server.2=cl-solr2:2888:3888
server.3=cl-solr3:2888:3888</code></pre></li>
<li><p>다음 명령어로 myid 파일을 zookeeper 서버 cl-solr1, cl-solr2 & cl-solr3에 각각 생성</p>
<pre><code>mkdir -p /var/lib/zookeeper/data/
echo 1 > /var/lib/zookeeper/data/myid --1 for cl-solr1 and 2 for cl-solr2 ..</code></pre></li>
</ul>
<h2 id="zookeeper-시작하기">zookeeper 시작하기</h2>
<pre><code>< zookeeper 설치 디렉토리 >/bin/zkServer.sh start
< zookeeper 설치 디렉토리 >/bin/zkServer.sh status</code></pre>
<h3 id="다음-명령어로-상태확인">다음 명령어로 상태확인</h3>
<pre><code>echo stat | nc cl-solr1 2181</code></pre>
<h2 id="solr-시작하기">SOLR 시작하기</h2>
<pre><code>< solr 설치 디렉토리 >/bin/solr start -c -z cl-solr1:2181,cl-solr2:2181,cl-solr3:2181 -h cl-solr1
< solr 설치 디렉토리 >/bin/solr start -c -z cl-solr1:2181,cl-solr2:2181,cl-solr3:2181 -h cl-solr2
< solr 설치 디렉토리 >/bin/solr start -c -z cl-solr1:2181,cl-solr2:2181,cl-solr3:2181 -h cl-solr3</code></pre>
<h2 id="새로운-컬렉션-생성">새로운 컬렉션 생성</h2>
<ol type="1">
<li><p>solr 노드중 한곳에서 다음 명령을 실행</p>
<pre><code>mkdir -p < solr 설치 디렉토리 >/server/solr/pats/conf</code></pre></li>
<li><p>현제 시스템에서 conf 폴더를 복사</p>
<pre><code>< solr 설치 디렉토리 >/bin/solr create -c my_collection_name -d < solr 설치 디렉토리 >/server/solr/pats/conf -n myname_cfg -shards 2 -replicationFactor 2</code></pre></li>
</ol>]]></description>
<pubDate>true</pubDate>
<guid>/posts/2017/02/05/SolrCloud-Setup-Instructions.html</guid>
<dc:creator>Young Gyu Park</dc:creator>
</item>
<item>
<title>Python pyenv, virtualenv, autoenv, venv 사용법 및 비교</title>
<link>/posts/2017/01/08/python_pyenv_virtualenv_autoenv.html</link>
<description><![CDATA[<h1 id="pyenv">pyenv</h1>
<h1 id="virtualenvwrapper">virtualenvwrapper</h1>
<h2 id="기본적인-설치법">기본적인 설치법</h2>
<p>$ pip install virtualenvwrapper</p>
<p>or:</p>
<p>$ sudo pip install virtualenvwrapper</p>
<!--more-->
<h2 id="쉘-시작-파일">쉘 시작 파일</h2>
<p>Add three lines to your shell startup file (.bashrc, .profile, etc.) to set the location where the virtual environments should live, the location of your development project directories, and the location of the script installed with this package:</p>
<p>다음 라인을 쉘 설정 파일(.bashrc, .profile, etc.)에 추가해 주세요.</p>
<p>export WORKON_HOME=<span class="math inline">\(HOME/.virtualenvs export PROJECT_HOME=\)</span>HOME/Devel source /usr/local/bin/virtualenvwrapper.sh</p>]]></description>
<pubDate>true</pubDate>
<guid>/posts/2017/01/08/python_pyenv_virtualenv_autoenv.html</guid>
<dc:creator>Young Gyu Park</dc:creator>
</item>
<item>
<title>Elasticsearch Reference</title>
<link>/posts/2016/12/13/elasticsearch_reference.html</link>
<description><![CDATA[<h1 id="document">Document</h1>
<h2 id="api-conventions">API Conventions</h2>
<p>elasticsearch REST API는 HTTP위에서 JSON을 사용합니다.</p>
<p>달리 명시되지 아니하는 한, 이 장에서 사용하는 컨벤션은 REST API를 통해서</p>
<!--more-->
<h3 id="multiple-indices">Multiple Indices</h3>
<p>Most APIs that refer to an index parameter support execution across multiple indices, using simple test1,test2,test3 notation (or _all for all indices). It also support wildcards, for example: test* or <em>test or te</em>t or <em>test</em>, and the ability to “add” (+) and “remove” (-), for example: +test*,-test3.</p>
<p>모든 멀티 인덱스 API들은 다음의 url query 문자열 파라메터를 지원한다: 이것은 또한 와일드카드도 지원한다. 예를 들면, test<em>, </em>test, te<em>t, </em>test* 그리고 플러스(+), 마이너스(-) 기호도 지원한다. 예를 들면, +test*, -test3</p>
<ul>
<li><p>ignore_unavailable 지정된 인덱스들이 가용하지 않을때 무시할지 말지를 정하는 제어 지시자. 이것은 또한 존재하지 않거나 닫힌 인덱스들도 포함한다. true 또는 false값을 가질 수 있다.</p></li>
<li><p>allow_no_indices 만약 와일드카드 인덱스 표현에 맞는 인덱스를 찾지 못하면 실패하기를 나타내는 제어지시자. true 또는 false값을 가질 수 있다. 예를 들면, 만약 와일드카드 foo*로 지정하고, foo로 시작하는 인덱스가 없을때, 이 설정값에따라 리퀘스트가 실패할것입니다. 이 설정은 또한 _all, * 또는 인덱스가 설정되어있지 않을경우에도 사용가능하다. 이 설정은 또한 알리아스가 닫힌 인덱스를 지정할때도 적용할 수 있다.</p></li>
</ul>
<p>expand_wildcards</p>
<p>Controls to what kind of concrete indices wildcard indices expression expand to. If open is specified then the wildcard expression is expanded to only open indices and if closed is specified then the wildcard expression is expanded only to closed indices. Also both values (open,closed) can be specified to expand to all indices. If none is specified then wildcard expansion will be disabled and if all is specified, wildcard expressions will expand to all indices (this is equivalent to specifying open,closed).</p>
<p>위의 파라메터에 대한 기본설정은 상용하는 api에 달려있다.</p>
<p>Note 단일 인덱스 API들, 예를 들면, 도큐먼트 API들 그리고 단일 인덱스 별칭 API들은 멀티 인덱스를 지원하지 않는다.</p>
<h3 id="date-math-support-in-index-names">Date math support in index names</h3>
<p>Date math index name resolution enables you to search a range of time-series indices, rather than searching all of your time-series indices and filtering the results or maintaining aliases. Limiting the number of indices that are searched reduces the load on the cluster and improves execution performance. For example, if you are searching for errors in your daily logs, you can use a date math name template to restrict the search to the past two days. Date math 인덱스 이름 해결책은 당신의 모든 시계열 인덱스들 검색하고 결과들을 필터링 또는</p>
<p>Almost all APIs that have an index parameter, support date math in the index parameter value.</p>
<p>A date math index name takes the following form:</p>
<p><static_name{date_math_expr{date_format|time_zone}}> Where:</p>
<p>static_name</p>
<p>is the static text part of the name</p>
<p>date_math_expr</p>
<p>is a dynamic date math expression that computes the date dynamically</p>
<p>date_format</p>
<p>is the optional format in which the computed date should be rendered. Defaults to YYYY.MM.dd.</p>
<p>time_zone</p>
<p>is the optional time zone . Defaults to utc.</p>
<p>You must enclose date math index name expressions within angle brackets, and all special characters should be URI encoded. For example:</p>
<pre><code># GET /<logstash-{now/d}>/_search
GET /%3Clogstash-%7Bnow%2Fd%7D%3E/_search
{
"query" : {
"match": {
"test": "data"
}
}
}</code></pre>
<p>COPY AS CURLVIEW IN CONSOLE Note Percent encoding of date math characters The special characters used for date rounding must be URI encoded as follows:</p>
<table>
<thead>
<tr class="header">
<th>Markdown</th>
<th>Less</th>
<th>Pretty</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><em>Still</em></td>
<td><code>renders</code></td>
<td><strong>nicely</strong></td>
</tr>
<tr class="even">
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr class="header">
<th><</th>
<th>%3C</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>></td>
<td>%3E</td>
</tr>
<tr class="even">
<td>/</td>
<td>%2F</td>
</tr>
<tr class="odd">
<td>{</td>
<td>%7B</td>
</tr>
<tr class="even">
<td>}</td>
<td>%7D</td>
</tr>
<tr class="odd">
<td>*</td>
<td>*</td>
</tr>
<tr class="even">
<td>+</td>
<td>%2B</td>
</tr>
<tr class="odd">
<td>:</td>
<td>%3A</td>
</tr>
</tbody>
</table>
<p>The following example shows different forms of date math index names and the final index names they resolve to given the current time is 22rd March 2024 noon utc.</p>
<p>Expression Resolves to <logstash-{now/d}></p>
<p>logstash-2024.03.22</p>
<p><logstash-{now/M}></p>
<p>logstash-2024.03.01</p>
<p><logstash-{now/M{YYYY.MM}}></p>
<p>logstash-2024.03</p>
<p><logstash-{now/M-1M{YYYY.MM}}></p>
<p>logstash-2024.02</p>
<p><logstash-{now/d{YYYY.MM.dd|+12:00}}></p>
<p>logstash-2024.03.23</p>
<p>To use the characters { and } in the static part of an index name template, escape them with a backslash , for example:</p>
<p><elastic\{ON\}-{now/M}> resolves to elastic{ON}-2024.03.01 The following example shows a search request that searches the Logstash indices for the past three days, assuming the indices use the default Logstash index name format, logstash-YYYY.MM.dd.</p>
<h1 id="get-logstash-nowd-2dlogstash-nowd-1dlogstash-nowd_search">GET /<logstash-{now/d-2d}>,<logstash-{now/d-1d}>,<logstash-{now/d}>/_search</h1>
<p>GET /%3Clogstash-%7Bnow%2Fd-2d%7D%3E%2C%3Clogstash-%7Bnow%2Fd-1d%7D%3E%2C%3Clogstash-%7Bnow%2Fd%7D%3E/_search { “query” : { “match”: { “test”: “data” } } }</p>
<h3 id="common-options">Common options</h3>
<h3 id="url-based-access-control">URL-based access control</h3>]]></description>
<pubDate>true</pubDate>
<guid>/posts/2016/12/13/elasticsearch_reference.html</guid>
<dc:creator>Young Gyu Park</dc:creator>
</item>
<item>
<title>Functor, Applicative, and Monad</title>
<link>/posts/2016/12/12/haskell_functor_applicative_monad.html</link>
<description><![CDATA[<p>https://www.schoolofhaskell.com/school/advanced-haskell/functors-applicative-functors-and-monads</p>
<p>아주 간단한 문제로 시작해봅시다. 우리는 사용자로부터 생일을 입력받기를 원합니다. 그리고, 2020년에 사용자의 나이를 알려주는 프로그램을 작성할 것입니다. read 함수를 사용한 아주 간단한 프로그램입니다.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true"></a> year <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In 2020, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> (<span class="dv">2020</span> <span class="op">-</span> <span class="fu">read</span> year)</span></code></pre></div>
<!--more-->
<p>만약 그 프로그램을 실행 후 유효한 년도를 입력하면, 올바른 답을 구하실 것입니다. 만약 이상한 년도 값을 입력하면 어떤 일이 벌어질까요?</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true"></a><span class="ex">Please</span> enter your birth year</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true"></a><span class="ex">hello</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true"></a><span class="ex">main.hs</span>: Prelude.read: no parse</span></code></pre></div>
<p>사용자 입력은 문자로 들어오고 그 문자를 Integer로 변환할려고 합니다. 그러나, 모든 문자들이 항상 유효한 Integer값은 아닙니다. read는 partial 함수입니다. 그것은 어떤 상황에서는 에러를 발생시킬수 있다는 것을 의미합니다.</p>
<p>좀더 견고한 프로그램을 작성하는 방법은 Maybe Integer 값을 반환하는 readMay함수를 쓰는것입니다. 이 함수는 그 파싱이 성공 또는 실패할지도 모르는 형들을 분명히 한다. 이것을 테스트할려면, 다음 코드를 실행해보세요. A more resilient way to write our code is to use the readMay function, which will return a Maybe Integer value. This makes it clear with the types themselves that the parse may succeed or fail. To test this out, try running the following code:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true"></a> <span class="co">-- We use explicit types to tell the compiler how to try and parse the</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true"></a> <span class="co">-- string.</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true"></a> <span class="fu">print</span> (readMay <span class="st">"1980"</span><span class="ot"> ::</span> <span class="dt">Maybe</span> <span class="dt">Integer</span>)</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true"></a> <span class="fu">print</span> (readMay <span class="st">"hello"</span><span class="ot"> ::</span> <span class="dt">Maybe</span> <span class="dt">Integer</span>)</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true"></a> <span class="fu">print</span> (readMay <span class="st">"2000"</span><span class="ot"> ::</span> <span class="dt">Maybe</span> <span class="dt">Integer</span>)</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true"></a> <span class="fu">print</span> (readMay <span class="st">"two-thousand"</span><span class="ot"> ::</span> <span class="dt">Maybe</span> <span class="dt">Integer</span>)</span></code></pre></div>
<p>그래서 어떻게 우리는 이 코드를 우리의 원래 문제를 풀기 위해서 사용할 수 있을까요? 우리는 readMay의 결과값 성공(Just) 또는 실패(Nothing)를 결정할 필요가 있습니다. 그 중 한 방법은 패턴 매칭을 사용하는 것입니다.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true"></a> yearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true"></a> <span class="kw">case</span> readMay yearString <span class="kw">of</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided an invalid year"</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true"></a> <span class="dt">Just</span> year <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In 2020, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> (<span class="dv">2020</span> <span class="op">-</span> year)</span></code></pre></div>
<p>디커필링 코드 이 코드는 약간 커플된 코드입니다. 이 코드를 사용자에게 출력을 출력하는 함수와 나이를 계산하는 또다른 함수로 나누어 보겠습니다.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided an invalid year"</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In 2020, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true"></a></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true"></a>yearToAge year <span class="ot">=</span> <span class="dv">2020</span> <span class="op">-</span> year</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true"></a></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true"></a> yearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true"></a> <span class="kw">case</span> readMay yearString <span class="kw">of</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dt">Nothing</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true"></a> <span class="dt">Just</span> year <span class="ot">-></span> <span class="dt">Just</span> (yearToAge year)</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>This code does exactly the same thing as our previous version. But the definition of maybeAge in the main function looks pretty repetitive to me. We check if the parse year is Nothing. If it’s Nothing, we return Nothing. If it’s Just, we return Just, after applying the function yearToAge. That seems like a lot of line noise to do something simple. All we want is to conditionally apply yearToAge. 이 코드는 이전 버전과 정확히 같은것을 합니다. 그러나, 저에게 메인 함수에 있는 maybeAge 정의는 반복되고 있는것 같습니다. 우리는 파싱된 년도가 Nothing인지 확인합니다. 만약 Nothing이면, Nothing을 반환할것입니다. 만약 Just면, Just를 반환합니다.</p>
<p>펑터 당행히도, 우리는 그것을 하는 헬퍼 함수를 가지고 있습니다. fmap 또는 펑터 맵핑은 어떤 함수를 펑터가 가지고 있는 값에 적용할것입니다. Maybe는 펑터의 한 예입니다. 또다른 흔한 예는 리스트입니다. Maybe의 경우에도 fmap이 정확히 위에서 기술된대로 작동할것입니다. 그래서 다음과 같이 바꿀 수 있습니다.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true"></a></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided an invalid year"</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In 2020, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true"></a>yearToAge year <span class="ot">=</span> <span class="dv">2020</span> <span class="op">-</span> year</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true"></a></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true"></a> yearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> <span class="fu">fmap</span> yearToAge (readMay yearString)</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>Our code definitely got shorter, and hopefully a bit clearer as well. Now it’s obvious that all we’re doing is applying the yearToAge function over the contents of the Maybe value.</p>
<p>So what is a functor? It’s some kind of container of values. In Maybe, our container holds zero or one values. With lists, we have a container for zero or more values. Some containers are even more exotic; the IO functor is actually providing an action to perform in order to retrieve a value. The only thing functors share is that they provide some fmap function which lets you modify their contents.</p>
<p>do-notation We have another option as well: we can use do-notation. This is the same way we’ve been writing our main function in so far. That’s because- as we mentioned in the previous paragraph- IO is a functor as well. Let’s see how we can change our code to not use fmap:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided an invalid year"</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In 2020, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true"></a></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true"></a>yearToAge year <span class="ot">=</span> <span class="dv">2020</span> <span class="op">-</span> year</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true"></a></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true"></a> yearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true"></a> yearInteger <span class="ot"><-</span> readMay yearString</span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true"></a> <span class="fu">return</span> <span class="op">$</span> yearToAge yearInteger</span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>Inside the do-block, we have the slurp operator <-. This operator is special for do-notation, and is used to pull a value out of its wrapper (in this case, Maybe). Once we’ve extracted the value, we can manipulate it with normal functions, like yearToAge. When we complete our do-block, we have to return a value wrapped up in that container again. That’s what the return function does.</p>
<p>do-notation isn’t available for all Functors; it’s a special feature reserved only for Monads. Monads are an extension of Functors that provide a little extra power. We’re not really taking advantage of any of that extra power here; we’ll need to make our program more complicated to demonstrate it.</p>
<p>Dealing with two variables It’s kind of limiting that we have a hard-coded year to compare against. Let’s fix that by allowing the user to specify the “future year.” We’ll start off with a simple implementation using pattern matching and then move back to do notation.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true"></a></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true"></a></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true"></a> <span class="kw">case</span> readMay birthYearString <span class="kw">of</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dt">Nothing</span></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true"></a> <span class="dt">Just</span> birthYear <span class="ot">-></span></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true"></a> <span class="kw">case</span> readMay futureYearString <span class="kw">of</span></span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dt">Nothing</span></span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true"></a> <span class="dt">Just</span> futureYear <span class="ot">-></span> <span class="dt">Just</span> (futureYear <span class="op">-</span> birthYear)</span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>OK, it gets the job done… but it’s very tedious. Fortunately, do-notation makes this kind of code really simple:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true"></a></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true"></a></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true"></a>yearDiff futureYear birthYear <span class="ot">=</span> futureYear <span class="op">-</span> birthYear</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true"></a></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true"></a> birthYear <span class="ot"><-</span> readMay birthYearString</span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true"></a> futureYear <span class="ot"><-</span> readMay futureYearString</span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true"></a> <span class="fu">return</span> <span class="op">$</span> yearDiff futureYear birthYear</span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>This is very convenient: we’ve now slurped our two values in our do-notation. If either parse returns Nothing, then the entire do-block will return Nothing. This demonstrates an important property about Maybe: it provides short circuiting.</p>
<p>Without resorting to other helper functions or pattern matching, there’s no way to write this code using just fmap. So we’ve found an example of code that requires more power than Functors provide, and Monads provide that power.</p>
<p>Partial application But maybe there’s something else that provides enough power to write our two-variable code without the full power of Monad. To see what this might be, let’s look more carefully at our types.</p>
<p>We’re working with two values: readMay birthYearString and readMay futureYearString. Both of these values have the type Maybe Integer. And we want to apply the function yearDiff, which has the type Integer -> Integer -> Integer.</p>
<p>If we go back to trying to use fmap, we’ll seemingly run into a bit of a problem. The type of fmap- specialized for Maybe and Integer- is (Integer -> a) -> Maybe Integer -> Maybe a. In other words, it takes a function that takes a single argument (an Integer) and returns a value of some type a, takes a second argument of a Maybe Integer, and gives back a value of type Maybe a. But our function- yearDiff- actually takes two arguments, not one. So fmap can’t be used at all, right?</p>
<p>Not true actually. This is where one of Haskell’s very powerful features comes into play. Any time we have a function of two arguments, we can also look at is as a function of one argument which returns a function. We can make this more clear with parentheses:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true"></a><span class="ot">yearDiff ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true"></a><span class="ot">yearDiff ::</span> <span class="dt">Integer</span> <span class="ot">-></span> (<span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span>)</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true"></a><span class="dt">So</span> how does that help us<span class="op">?</span> <span class="dt">We</span> can look at the <span class="fu">fmap</span> function as<span class="op">:</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true"></a></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true"></a><span class="fu">fmap</span><span class="ot"> ::</span> (<span class="dt">Integer</span> <span class="ot">-></span> (<span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span>))</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true"></a> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Maybe</span> (<span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span>)</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true"></a><span class="dt">Then</span> when we apply <span class="fu">fmap</span> to yearDiff, we end up with<span class="op">:</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true"></a></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true"></a><span class="fu">fmap</span><span class="ot"> yearDiff ::</span> <span class="dt">Maybe</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Maybe</span> (<span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span>)</span></code></pre></div>
<p>That’s pretty cool. We can apply this to our readMay futureYearString and end up with:</p>
<p>fmap yearDiff (readMay futureYearString) :: Maybe (Integer -> Integer) That’s certainly very interesting, but it doesn’t help us. We need to somehow apply this value of type Maybe (Integer -> Integer) to our readMay birthYearString of type Maybe Integer. We can do this with do-notation:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true"></a></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true"></a></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true"></a>yearDiff futureYear birthYear <span class="ot">=</span> futureYear <span class="op">-</span> birthYear</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true"></a></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true"></a> yearToAge <span class="ot"><-</span> <span class="fu">fmap</span> yearDiff (readMay futureYearString)</span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true"></a> birthYear <span class="ot"><-</span> readMay birthYearString</span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true"></a> <span class="fu">return</span> <span class="op">$</span> yearToAge birthYear</span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>We can even use fmap twice and avoid the second slurp:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true"></a></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true"></a>yearDiff futureYear birthYear <span class="ot">=</span> futureYear <span class="op">-</span> birthYear</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true"></a></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true"></a> yearToAge <span class="ot"><-</span> <span class="fu">fmap</span> yearDiff (readMay futureYearString)</span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true"></a> <span class="fu">fmap</span> yearToAge (readMay birthYearString)</span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>But we don’t have a way to apply our Maybe (Integer -> Integer) function to our Maybe Integer directly.</p>
<p>Applicative functors And now we get to our final concept: applicative functors. The idea is simple: we want to be able to apply a function which is inside a functor to a value inside a functor. The magic operator for this is <*>. Let’s see how it works in our example:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Control.Applicative</span> ((<*>))</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true"></a></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true"></a></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true"></a>yearDiff futureYear birthYear <span class="ot">=</span> futureYear <span class="op">-</span> birthYear</span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true"></a></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span></span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true"></a> <span class="fu">fmap</span> yearDiff (readMay futureYearString)</span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true"></a> <span class="op"><*></span> readMay birthYearString</span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>In fact, the combination of fmap and <*> is so common that we have a special operator, <$>, which is a synonym for fmap. That means we can make our code just a little prettier:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Control.Applicative</span> ((<$>), (<*>))</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true"></a></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true"></a></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true"></a>yearDiff futureYear birthYear <span class="ot">=</span> futureYear <span class="op">-</span> birthYear</span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true"></a></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true"></a><span class="co">-- show</span></span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> yearDiff</span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true"></a> <span class="op"><$></span> readMay futureYearString</span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true"></a> <span class="op"><*></span> readMay birthYearString</span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true"></a><span class="co">-- /show</span></span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>Notice the distinction between <$> and <*>. The former uses a function which is not wrapped in a functor, while the latter applies a function which is wrapped up.</p>
<p>So we don’t need Monads? So if we can do such great stuff with functors and applicative functors, why do we need monads at all? The terse answer is context sensitivity: with a monad, you can make decisions on which processing path to follow based on previous results. With applicative functors, you have to always apply the same functions.</p>
<p>Let’s give a contrived example: if the future year is less than the birth year, we’ll assume that the user just got confused and entered the values in reverse, so we’ll automatically fix it by reversing the arguments to yearDiff. With do-notation and an if statement, it’s easy:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true"></a></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true"></a></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true"></a>yearDiff futureYear birthYear <span class="ot">=</span> futureYear <span class="op">-</span> birthYear</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true"></a></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true"></a> futureYear <span class="ot"><-</span> readMay futureYearString</span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true"></a> birthYear <span class="ot"><-</span> readMay birthYearString</span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true"></a> <span class="fu">return</span> <span class="op">$</span></span>
<span id="cb15-19"><a href="#cb15-19" aria-hidden="true"></a> <span class="kw">if</span> futureYear <span class="op"><</span> birthYear</span>
<span id="cb15-20"><a href="#cb15-20" aria-hidden="true"></a> <span class="kw">then</span> yearDiff birthYear futureYear</span>
<span id="cb15-21"><a href="#cb15-21" aria-hidden="true"></a> <span class="kw">else</span> yearDiff futureYear birthYear</span>
<span id="cb15-22"><a href="#cb15-22" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>Exercises Implement fmap using <*> and return.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Control.Applicative</span> ((<*>), <span class="dt">Applicative</span>)</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Prelude</span> (return, <span class="dt">Monad</span>)</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Prelude</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true"></a></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true"></a><span class="fu">fmap</span><span class="ot"> ::</span> (<span class="dt">Applicative</span> m, <span class="dt">Monad</span> m) <span class="ot">=></span> (a <span class="ot">-></span> b) <span class="ot">-></span> (m a <span class="ot">-></span> m b)</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true"></a><span class="co">-- show</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true"></a><span class="fu">fmap</span> <span class="op">...</span> <span class="op">...</span> <span class="ot">=</span> <span class="dt">FIXME</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true"></a><span class="co">-- /show</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true"></a></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true"></a>main <span class="ot">=</span></span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true"></a> <span class="kw">case</span> <span class="fu">fmap</span> (<span class="op">Prelude.+</span> <span class="dv">1</span>) (<span class="dt">Prelude.Just</span> <span class="dv">2</span>) <span class="kw">of</span></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true"></a> <span class="dt">Prelude.Just</span> <span class="dv">3</span> <span class="ot">-></span> Prelude.putStrLn <span class="st">"Good job!"</span></span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true"></a> _ <span class="ot">-></span> Prelude.putStrLn <span class="st">"Try again"</span></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Control.Applicative</span> ((<*>))</span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true"></a></span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true"></a><span class="co">-- show</span></span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true"></a>myFmap function wrappedValue <span class="ot">=</span> <span class="fu">return</span> function <span class="op"><*></span> wrappedValue</span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true"></a></span>
<span id="cb16-19"><a href="#cb16-19" aria-hidden="true"></a>main <span class="ot">=</span> <span class="fu">print</span> <span class="op">$</span> myFmap (<span class="op">+</span> <span class="dv">1</span>) <span class="op">$</span> <span class="dt">Just</span> <span class="dv">5</span></span>
<span id="cb16-20"><a href="#cb16-20" aria-hidden="true"></a><span class="co">-- /show</span></span>
<span id="cb16-21"><a href="#cb16-21" aria-hidden="true"></a><span class="dt">How</span> is <span class="fu">return</span> implemented for the <span class="dt">Maybe</span> monad<span class="op">?</span> <span class="dt">Try</span> replacing <span class="fu">return</span> with its implementation <span class="kw">in</span> the code above<span class="op">.</span></span>
<span id="cb16-22"><a href="#cb16-22" aria-hidden="true"></a></span>
<span id="cb16-23"><a href="#cb16-23" aria-hidden="true"></a><span class="co">-- show</span></span>
<span id="cb16-24"><a href="#cb16-24" aria-hidden="true"></a>returnMaybe <span class="ot">=</span> <span class="dt">FIXME</span></span>
<span id="cb16-25"><a href="#cb16-25" aria-hidden="true"></a><span class="co">-- /show</span></span>
<span id="cb16-26"><a href="#cb16-26" aria-hidden="true"></a></span>
<span id="cb16-27"><a href="#cb16-27" aria-hidden="true"></a>main</span>
<span id="cb16-28"><a href="#cb16-28" aria-hidden="true"></a> <span class="op">|</span> returnMaybe <span class="st">"Hello"</span> <span class="op">==</span> <span class="dt">Just</span> <span class="st">"Hello"</span> <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">"Correct!"</span></span>
<span id="cb16-29"><a href="#cb16-29" aria-hidden="true"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">"Incorrect, please try again"</span></span>
<span id="cb16-30"><a href="#cb16-30" aria-hidden="true"></a><span class="fu">return</span> is simply the <span class="dt">Just</span> constructor<span class="op">.</span> <span class="dt">This</span> gets defined as<span class="op">:</span></span>
<span id="cb16-31"><a href="#cb16-31" aria-hidden="true"></a></span>
<span id="cb16-32"><a href="#cb16-32" aria-hidden="true"></a><span class="kw">instance</span> <span class="dt">Monad</span> <span class="dt">Maybe</span> <span class="kw">where</span></span>
<span id="cb16-33"><a href="#cb16-33" aria-hidden="true"></a> <span class="fu">return</span> <span class="ot">=</span> <span class="dt">Just</span></span></code></pre></div>
<p>yearDiff is really just subtraction. Try to replace the calls to yearDiff with explicit usage of the - operator.</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true"></a></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true"></a></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true"></a> futureYear <span class="ot"><-</span> readMay futureYearString</span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true"></a> birthYear <span class="ot"><-</span> readMay birthYearString</span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true"></a> <span class="fu">return</span> <span class="op">$</span></span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true"></a><span class="co">-- show</span></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true"></a> <span class="kw">if</span> futureYear <span class="op"><</span> birthYear</span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true"></a> <span class="kw">then</span> yearDiff birthYear futureYear</span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true"></a> <span class="kw">else</span> yearDiff futureYear birthYear</span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true"></a><span class="co">-- /show</span></span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true"></a> displayAge maybeAge</span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true"></a></span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb17-27"><a href="#cb17-27" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb17-28"><a href="#cb17-28" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb17-29"><a href="#cb17-29" aria-hidden="true"></a></span>
<span id="cb17-30"><a href="#cb17-30" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-31"><a href="#cb17-31" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb17-32"><a href="#cb17-32" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb17-33"><a href="#cb17-33" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb17-34"><a href="#cb17-34" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb17-35"><a href="#cb17-35" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb17-36"><a href="#cb17-36" aria-hidden="true"></a> futureYear <span class="ot"><-</span> readMay futureYearString</span>
<span id="cb17-37"><a href="#cb17-37" aria-hidden="true"></a> birthYear <span class="ot"><-</span> readMay birthYearString</span>
<span id="cb17-38"><a href="#cb17-38" aria-hidden="true"></a> <span class="fu">return</span> <span class="op">$</span></span>
<span id="cb17-39"><a href="#cb17-39" aria-hidden="true"></a><span class="co">-- show</span></span>
<span id="cb17-40"><a href="#cb17-40" aria-hidden="true"></a> <span class="kw">if</span> futureYear <span class="op"><</span> birthYear</span>
<span id="cb17-41"><a href="#cb17-41" aria-hidden="true"></a> <span class="kw">then</span> birthYear <span class="op">-</span> futureYear</span>
<span id="cb17-42"><a href="#cb17-42" aria-hidden="true"></a> <span class="kw">else</span> futureYear <span class="op">-</span> birthYear</span>
<span id="cb17-43"><a href="#cb17-43" aria-hidden="true"></a><span class="co">-- /show</span></span>
<span id="cb17-44"><a href="#cb17-44" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>It’s possible to write an applicative functor version of the auto-reverse-arguments code by modifying the yearDiff function. Try to do so.</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Control.Applicative</span> ((<$>), (<*>))</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true"></a></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true"></a></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true"></a><span class="co">-- show</span></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true"></a>yearDiff futureYear birthYear <span class="ot">=</span> <span class="dt">FIXME</span></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true"></a><span class="co">-- /show</span></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true"></a></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true"></a>main</span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true"></a> <span class="op">|</span> yearDiff <span class="dv">5</span> <span class="dv">6</span> <span class="op">==</span> <span class="dv">1</span> <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">"Correct!"</span></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">"Please try again"</span></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true"></a></span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true"></a></span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true"></a><span class="co">-- show</span></span>
<span id="cb18-24"><a href="#cb18-24" aria-hidden="true"></a>yearDiff futureYear birthYear</span>
<span id="cb18-25"><a href="#cb18-25" aria-hidden="true"></a> <span class="op">|</span> futureYear <span class="op">></span> birthYear <span class="ot">=</span> futureYear <span class="op">-</span> birthYear</span>
<span id="cb18-26"><a href="#cb18-26" aria-hidden="true"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> birthYear <span class="op">-</span> futureYear</span>
<span id="cb18-27"><a href="#cb18-27" aria-hidden="true"></a><span class="co">-- /show</span></span>
<span id="cb18-28"><a href="#cb18-28" aria-hidden="true"></a></span>
<span id="cb18-29"><a href="#cb18-29" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb18-30"><a href="#cb18-30" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb18-31"><a href="#cb18-31" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb18-32"><a href="#cb18-32" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb18-33"><a href="#cb18-33" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb18-34"><a href="#cb18-34" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb18-35"><a href="#cb18-35" aria-hidden="true"></a> futureYear <span class="ot"><-</span> readMay futureYearString</span>
<span id="cb18-36"><a href="#cb18-36" aria-hidden="true"></a> birthYear <span class="ot"><-</span> readMay birthYearString</span>
<span id="cb18-37"><a href="#cb18-37" aria-hidden="true"></a> <span class="fu">return</span> <span class="op">$</span></span>
<span id="cb18-38"><a href="#cb18-38" aria-hidden="true"></a> <span class="kw">if</span> futureYear <span class="op"><</span> birthYear</span>
<span id="cb18-39"><a href="#cb18-39" aria-hidden="true"></a> <span class="kw">then</span> yearDiff birthYear futureYear</span>
<span id="cb18-40"><a href="#cb18-40" aria-hidden="true"></a> <span class="kw">else</span> yearDiff futureYear birthYear</span>
<span id="cb18-41"><a href="#cb18-41" aria-hidden="true"></a> displayAge maybeAge</span></code></pre></div>
<p>Now try to do it without modifying yearDiff directly, but by using a helper function which is applied to yearDiff.</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Control.Applicative</span> ((<$>), (<*>))</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true"></a></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true"></a></span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true"></a>yearDiff futureYear birthYear <span class="ot">=</span> futureYear <span class="op">-</span> birthYear</span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true"></a><span class="co">-- show</span></span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true"></a>yourHelperFunction f <span class="op">...</span></span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true"></a><span class="co">-- /show</span></span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true"></a></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true"></a>main</span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true"></a> <span class="op">|</span> yourHelperFunction yearDiff <span class="dv">5</span> <span class="dv">6</span> <span class="op">==</span> <span class="dv">1</span> <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">"Correct!"</span></span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">"Please try again"</span></span>
<span id="cb19-17"><a href="#cb19-17" aria-hidden="true"></a><span class="kw">import</span> <span class="dt">Safe</span> (readMay)</span>
<span id="cb19-18"><a href="#cb19-18" aria-hidden="true"></a></span>
<span id="cb19-19"><a href="#cb19-19" aria-hidden="true"></a>displayAge maybeAge <span class="ot">=</span></span>
<span id="cb19-20"><a href="#cb19-20" aria-hidden="true"></a> <span class="kw">case</span> maybeAge <span class="kw">of</span></span>
<span id="cb19-21"><a href="#cb19-21" aria-hidden="true"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="st">"You provided invalid input"</span></span>
<span id="cb19-22"><a href="#cb19-22" aria-hidden="true"></a> <span class="dt">Just</span> age <span class="ot">-></span> <span class="fu">putStrLn</span> <span class="op">$</span> <span class="st">"In that year, you will be: "</span> <span class="op">++</span> <span class="fu">show</span> age</span>
<span id="cb19-23"><a href="#cb19-23" aria-hidden="true"></a></span>
<span id="cb19-24"><a href="#cb19-24" aria-hidden="true"></a>yearDiff futureYear birthYear <span class="ot">=</span> futureYear <span class="op">-</span> birthYear</span>
<span id="cb19-25"><a href="#cb19-25" aria-hidden="true"></a></span>
<span id="cb19-26"><a href="#cb19-26" aria-hidden="true"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb19-27"><a href="#cb19-27" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter your birth year"</span></span>
<span id="cb19-28"><a href="#cb19-28" aria-hidden="true"></a> birthYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb19-29"><a href="#cb19-29" aria-hidden="true"></a> <span class="fu">putStrLn</span> <span class="st">"Please enter some year in the future"</span></span>
<span id="cb19-30"><a href="#cb19-30" aria-hidden="true"></a> futureYearString <span class="ot"><-</span> <span class="fu">getLine</span></span>
<span id="cb19-31"><a href="#cb19-31" aria-hidden="true"></a> <span class="kw">let</span> maybeAge <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb19-32"><a href="#cb19-32" aria-hidden="true"></a> futureYear <span class="ot"><-</span> readMay futureYearString</span>
<span id="cb19-33"><a href="#cb19-33" aria-hidden="true"></a> birthYear <span class="ot"><-</span> readMay birthYearString</span>
<span id="cb19-34"><a href="#cb19-34" aria-hidden="true"></a> <span class="fu">return</span> <span class="op">$</span></span>
<span id="cb19-35"><a href="#cb19-35" aria-hidden="true"></a> <span class="kw">if</span> futureYear <span class="op"><</span> birthYear</span>
<span id="cb19-36"><a href="#cb19-36" aria-hidden="true"></a> <span class="kw">then</span> yourHelperFunction yearDiff birthYear futureYear</span>
<span id="cb19-37"><a href="#cb19-37" aria-hidden="true"></a> <span class="kw">else</span> yourHelperFunction yearDiff futureYear birthYear</span>
<span id="cb19-38"><a href="#cb19-38" aria-hidden="true"></a> displayAge maybeAge</span>
<span id="cb19-39"><a href="#cb19-39" aria-hidden="true"></a></span>
<span id="cb19-40"><a href="#cb19-40" aria-hidden="true"></a><span class="co">-- show</span></span>
<span id="cb19-41"><a href="#cb19-41" aria-hidden="true"></a>yourHelperFunction f x y</span>
<span id="cb19-42"><a href="#cb19-42" aria-hidden="true"></a> <span class="op">|</span> x <span class="op">></span> y <span class="ot">=</span> f x y</span>
<span id="cb19-43"><a href="#cb19-43" aria-hidden="true"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> f y x</span>
<span id="cb19-44"><a href="#cb19-44" aria-hidden="true"></a><span class="co">-- /show</span></span></code></pre></div>]]></description>
<pubDate>true</pubDate>
<guid>/posts/2016/12/12/haskell_functor_applicative_monad.html</guid>
<dc:creator>Young Gyu Park</dc:creator>
</item>
<item>
<title>Today, food travels thousands of miles from farms to consumers. Why does this happen?</title>
<link>/posts/2016/06/02/ielts_writing_food_travels.html</link>
<description><![CDATA[<p>Is this a positive or negative trend?</p>
<p>Nowadays, most of food we eat everyday is comming from thousands miles away even though some identical local food is available for purchasing. In this essay, I will dwell on why it is consistent and examine what impact it brought to our lives.</p>
<div>
</div>
<!--more-->
<p>First of all, technological advances in food transportation along with cheap oil price have allowed food industry to move greater quantities of food faster and over longer distances than ever before. More specifically, air transportation, high-speed rails and a cold-storage car are the ones which enable food to travel such a long distance. In addition to this, the high demand for food in a such densely populated city is a driving force to precipitate these technological development because locally grown food cannot meet such a high demand. Accordingly, it is inevitable to use those technological advancement to unravel the food shortage problem in such densely populated cities.</p>
<p>It is clear that this change has brought many negative effects to our lives in many respects. One ot the most detrimental effects is that most of food relying on long journey have to be processed with much toxic checmical to preserve the freshness of the products or prevent the food from decay. Such process will also cause many unexpected problems such as diseases caused by intake of the food, additional environmental contamination from the checmical process of the food. Additionally, the transportation of the food will also contribute to the aggravating global warming issue, since the food need to be delivered from the place it grow to a city in which most of consumer live.</p>
<p>In summary, the two most important factors, which are technological advances and food shortage in a densely populated city, are the main contributors to make this trend feasible. In my opinion, such trend seems to have many adverse effects and thus it is desirable to encourage people to consume more locally grown food and curtail the increasing population in a city.</p>]]></description>
<pubDate>true</pubDate>
<guid>/posts/2016/06/02/ielts_writing_food_travels.html</guid>
<dc:creator>Young Gyu Park</dc:creator>
</item>
<item>
<title>Traffic jams are a problem in many towns and cities. Some people suggest that governments should build wider roads in order to solve the problem</title>
<link>/posts/2016/06/01/ielts_writing_traffic_jams.html</link>
<description><![CDATA[<p>Do you agree or disagree?</p>
<p>Aggravating traffic congestion is a major concern to many cities. Many people suggest different solutions for the problem. One of the solutions that is commonly debated is that governments should take a policy to construct wider roads which will target to increase the capacities of the roads to contain more cars. However, I firmly object the idea since the manner cannot be the ultimate solution for the problem.</p>
<div>
</div>
<!--more-->
<p>To begin with, it is not a very desirable idea to build a wider road since it will hamper the vitality of the city in various ways. More specifically, the policy to build a wider road will not make a city more livable as a city more focused on development for the convenience of the driver will not be a place where many people want to live. For example, there is a newly built city with 10 lanes of road in Brazil because they want to build a city which free from the common traffic jams problem. However, they sooner or later encounter another problem that nobody want to live the city because the city is only considering traffic issue by building a wide road.</p>
<p>Secondly, the effort to build a wider road will create more incentives for people to buy more cars, which exacerbate the traffic congestion again. It is ironic that the solution to lessen traffic congestion is actually contributing to make the problem worsen. For instance, about ten years ago, a mayor in my city announced a very robust plan to build wider roads to reslove the worsening traffic jams. However, the plan seems to be effective temporary but the convenience the plan brought palyed a role as an incentive to attract more people to buying cars.</p>
<p>In conclusion, I absolutely agree with the idea that governments should not abandon any policies to extend the road to alleviate the deteriorating traffic problem. Therefore, governments need to come up with idea as to how to reduce the number of cars instead of widening roads.</p>]]></description>
<pubDate>true</pubDate>
<guid>/posts/2016/06/01/ielts_writing_traffic_jams.html</guid>
<dc:creator>Young Gyu Park</dc:creator>
</item>
<item>
<title>Some working parents believe that child-care centers provide the best care for their children. However, others think family members, such as grandparents, provide the best care</title>
<link>/posts/2016/05/31/ielts_writing_child_care.html</link>
<description><![CDATA[<p>Discuss both views and give your own opinion.</p>
<p>It is quite controversial that childcare facilities will be the best place for children to be well taken care of, since other people believe that family members should be in charge of raising kids. In this essay, I will examine the two condradicting views and add my thought on the subject.</p>
<p>To begin with, it is no doubt that child-care facilities are more competent in comparison of child’s relatives in terms of taking care of children. This is because people who are working in the child-care centers are required to be trained and educated in a university or special education centers for childcare, which ehnace their speciality in childcare. In addition to this, most of child-care facilities are well designed and specialized to serve the purpose of nurturing kids, which is believed to be lacking in family home.</p>
<p>On the other hand, the most evident advantage we can gain from relatives involvement of nurturing children is that they can take care of kids with affection and interest. However, it is hard to find such strong affection and interest in child-care centers as people in the centers usually do not have any emotional connection with the kids they are raising. Another benefit from raising kids with the help of family members is that we can nurture children in the most comfortable environment, which is abosultely conducive to ensure a sense of security.</p>
<p>To sum up, the two differen point of views with regard to raising kids by family members or child-care centers seem to have their own advantages and disadvantages. In my opinion, raising kids with family members seems to provide the best environment for the kids in various aspects.</p>]]></description>
<pubDate>true</pubDate>
<guid>/posts/2016/05/31/ielts_writing_child_care.html</guid>
<dc:creator>Young Gyu Park</dc:creator>
</item>
<item>
<title>Nowadays, people have unhealthy diets and do not do enough exercise</title>
<link>/posts/2016/05/30/ielts_writing_unhealthy_diets_exercise.html</link>
<description><![CDATA[<p>Discuss the reasons for this and make suggestions on how to encourage people to have healthy lifestyles.</p>
<p>It is a grave concern in most societies that people are experiencing many health problems caused by instant food and lack of exercise. In this essay, I will analyze the reasons why this problems are persistent and probe what other solutions we can adopt to rein the increasing trend.</p>
<p>First of all, the most evident reason of encouraging people to have unhealthy food and discouraging people to have less exercise is people’s overloaded work. As the competition among people is severe, people hesitate to spend enough time to prepare a food and to exercise in gym. This is because they believe that the saved time from cooking food and not exercising can direct at enhancing their competitiveness in various aspects in a soceity. Thus their reckless and frequent intake of instant food and negligence in exercise resulted in the current health problem.</p>
<p>Accordingly, the most imminent task to mitigate the aggravating health issue among people is to lessen people’ work load, which will give some time to review themselves in terms of health. Furthermore, a community’s collective effort to curtail the accelerating competition in our soceity is also beneficial to minimize the worsening consequence of people’s health. Hence, soceity as a whole need to find out a way to reduce the level of competition and provide a specific policy to extricate people from their busy work.</p>
<p>In conclusion, the health probem seem to lie in the social structure to evoke more competition trying to exract more outcome from the employees, which endanger people’s health. Therefore, it is crucial to eradicate</p>]]></description>
<pubDate>true</pubDate>
<guid>/posts/2016/05/30/ielts_writing_unhealthy_diets_exercise.html</guid>
<dc:creator>Young Gyu Park</dc:creator>
</item>
<item>
<title>As well as making money, businesses also have social responsibilities.</title>
<link>/posts/2016/05/27/ielts_writing_business_responsibilities.html</link>
<description><![CDATA[<p>To what extent do you agree or disagree with this statement?</p>
<p>There is no denying that business have been large part of human activity. As the influence of business is increasing, people start to contemplate and require the social responsibility of a business. In my opinion, it is absurd argument that a business is completely free from the social responsibility because it is the organization for the purpose of pursuing profit.</p>
<p>To begin with, any human activities including business should take a certain amount of social responsibility because they are inextricably interwined with other people’s lives. For instance, if a factory release contaminated water into river without taking proper measure to purify the water, it might lead to jeopardizing other people’s lives. Considering the nature of business which prioritize the profit, it seems quite natural for the owner of the business to take an action to minimize the cost, which serve well the purpose of the business while hampering the quality of other people’s lives.</p>
<p>Secondly, most of business which is reluctant to fulfill their social responsibility seems to end up with the failure of the business because it will lose the customers’ trust. For example, the most prestigious company in my country did not faithfully conduct the rules to protect its employees from the hazardous material, which cause many employees’ lives. As a result, they cannot help but lose very large portion of market share due to the incident which lead to campaign against , which might result in the bankruptcy of the business.</p>
<p>In conclusion, it is necessarily not only for the success of a business but the community we live that any businesses pursuing profit should abide by the principles to serve social responsibilities. Therefore, we need to encourage businesses people to participate this movement to make our societies a better place by asking them to respect social responsibilities.</p>]]></description>
<pubDate>true</pubDate>
<guid>/posts/2016/05/27/ielts_writing_business_responsibilities.html</guid>
<dc:creator>Young Gyu Park</dc:creator>
</item>
</channel>
</rss>