@@ -249,18 +249,16 @@ ghci> :t (<*>) @IO
249
249
- 第2引数(右辺)の` IO a ` : 「第1引数の命令が返す関数」の引数と同じ型` a ` を返す命令。
250
250
- 戻り値の` IO b ` : 「第1引数の命令が返す関数」の戻り値と同じ型` b ` を返す命令。
251
251
252
- 第1引数の` IO (a -> b) ` がかなり変わっている 。` a -> b ` を返す命令なんて一体どこから出てくるのか
252
+ 第1引数の` IO (a -> b) ` がかなり変わっていますね 。` a -> b ` を返す命令なんて一体どこから出てくるのでしょうか?その答えは、先ほどの ` (++) <$> getLine <*> getLine ` という式における ` <*> ` の左辺、 ` (++) <$> getLine ` にあります:
253
253
254
- その答えは、先ほどの` (++) <$> getLine <*> getLine ` という式における` <*> ` の左辺、` (++) <$> getLine ` にあります。
255
-
256
- ```
254
+ ``` haskell
257
255
ghci> : t (++) <$> getLine
258
256
(++) <$> getLine :: IO ([Char ] -> [Char ])
259
257
```
260
258
261
259
` IO ([Char] -> [Char]) ` 、すなわち「『文字列を受け取って文字列を返す関数』を返す命令」が出てきました!
262
260
263
- 以下のように型が推論された結果です。
261
+ 以下のように ` <$> ` の型変数 ` a ` ・ ` b ` ・ ` f ` が推論された結果です:
264
262
265
263
``` haskell
266
264
(++) <$> getLine
@@ -277,25 +275,20 @@ ghci> :t (++) <$> getLine
277
275
f b
278
276
```
279
277
280
- ` ++ ` のような2つ以上の引数を受け取る関数を` <$> ` に渡した場合、必ずこのような型が現れます。
281
- Haskellでは2つ以上の引数を受け取る関数は` a -> b -> c ` (カッコを補うと「` a -> (b -> c) ` 」)という型の、「引数を1つ受け取ると、『残りの引数を受け取る関数』を返す関数」で表現されるので、` <$> ` を使った結果に「関数を返す命令」が現れるのは、ある意味当然なことなのです。
278
+ ` ++ ` のような2つ以上の引数を受け取る関数を` <$> ` に渡した場合、必ずこのように` IO ` の中に関数を含んだ型が現れます。Haskellでは2つ以上の引数を受け取る関数は` a -> b -> c ` (カッコを補うと「` a -> (b -> c) ` 」)という型の、「引数を1つ受け取ると、『残りの引数を受け取る関数』を返す関数」で表現されるので、` <$> ` を使った結果に「関数を返す命令」が現れるのは、当然なことなのです。
282
279
283
- こうした場合に対応するのが` <*> ` の役目です。
284
- 改めて型宣言を思い出してみましょう。
280
+ こうした場合に対応するのが` <*> ` の役目です。改めて型宣言を思い出してみましょう:
285
281
286
- ```
282
+ ``` haskell
287
283
ghci> : t (<*>) @ IO
288
284
(<*>) @ IO :: IO (a -> b ) -> IO a -> IO b
289
285
```
290
286
291
- 2つ以上の引数を受け取る関数を` <$> ` に渡した結果現れる、` IO (a -> b) ` のような型の値を左辺に受け取ることがはっきりと書かれていますね。
292
- そして、右辺で受け取っているのは、また命令です。「『第1引数の命令が返す関数』の引数と同じ型` a ` を返す命令」であることから、左辺に渡された命令が返す関数に渡されることが予期されます。
293
- 結果、最終的に` <*> ` が返すのは、やっぱり命令です。「『第1引数の命令が返す関数』の戻り値と同じ型` b ` を返す命令」とあるとおり、やはり左辺に渡された命令が返す関数の結果をそのまま返す命令なんでしょう。
287
+ 2つ以上の引数を受け取る関数を` <$> ` に渡した結果現れる、` IO (a -> b) ` 型の値を左辺に受け取ることがはっきりと書かれていますね。そして右辺で受け取っているのは、また命令です。「『第1引数の命令が返す関数』の引数と同じ型` a ` を返す命令」であることから、第1引数に渡された命令が返す関数に渡されることが予期されます。結果、最終的に` <*> ` が返すのは、やっぱり命令です。「『第1引数の命令が返す関数』の戻り値と同じ型` b ` を返す命令」とあるとおり、やはり第1引数に渡された命令が返す関数の結果をそのまま返す命令なんでしょう。
294
288
295
- ここで出てきた` IO a ` から結果となる値` a ` を取り出して、` IO (a -> b) ` の結果となる` a -> b ` に渡すには、` IO (a -> b) ` と` IO a ` 、両方を実行する必要があります。
296
- 下記のような関数を書いて、実際に` <*> ` が左辺の` IO (a -> b) ` と右辺の` IO a ` の両方を実行していることを確かめてみましょう。
289
+ ここで出てきた` IO a ` から結果となる` a ` 型の値を取り出して、` IO (a -> b) ` の結果となる` a -> b ` に渡すには、` IO (a -> b) ` と` IO a ` 、両方を実行する必要があります。下記のような関数を書いて、実際に` <*> ` が左辺の` IO (a -> b) ` と右辺の` IO a ` の両方を実行していることを確かめてみましょう:
297
290
298
- ```
291
+ ``` haskell
299
292
-- 関数を返す前に`putStrLn`を実行する命令
300
293
returnDoubler :: IO (Integer -> Integer )
301
294
returnDoubler = do
@@ -309,83 +302,72 @@ return4 = do
309
302
return 4
310
303
```
311
304
312
- ```
305
+ ``` haskell
313
306
ghci> returnDoubler <*> return4
314
307
Returning a function
315
308
Returning 4
316
309
8
317
310
```
318
311
319
- ` returnDoubler ` に書いた` putStrLn ` の後に、` return4 ` に書いた` putStrLn ` が実行されましたね。
320
- そう、` <*> ` は、左辺に渡した「関数を返す命令」を実行した後に、右辺に渡した「値を返す命令」を順番に実行しているのです。
321
-
322
- 以上から、` <*> ` は、` <$> ` が返した「関数を返す` IO ` (命令)」と、` <*> ` の右辺に渡したもう一つの` IO ` (命令)を** 続けて実行する** ための演算子であることがわかります。
312
+ ` returnDoubler ` に書いた` putStrLn ` の後に、` return4 ` に書いた` putStrLn ` が実行されましたね。そう、` <*> ` は、左辺に渡した「関数を返す命令」と、右辺に渡した「値を返す命令」を順番に実行しているのです。
323
313
324
- ` < $>` は、あくまでも** 1つの** 命令に対して結果を関数に渡す役割である一方 、` <*> ` は、** 2つ以上の** 命令を、続けて実行して関数に渡す、ということを覚えておきましょう 。
314
+ 以上から、 ` <*> ` は、 ` < $>` が返した「関数を返す ` IO ` (命令)」と、 ` <*> ` の右辺に渡したもう一つの ` IO ` (命令)を ** 続けて実行する ** ための演算子であることがわかります。 ` <$> ` は、あくまでも** 1つの** 命令の結果を関数に渡す役割である一方 、` <*> ` は、** 2つ以上の** 命令を続けて実行して関数に渡す、という点を覚えておいてください 。
325
315
326
- 「2つ以上」と書いたとおり、当然3つ以上の引数を受け取る関数に対しても` <*> ` は使えます。
327
- 例えば、今回の課題で定義しておくと便利であろう、「元金と金利(単位はパーセント)と年数を受け取って、年数後の元金を返す」関数を定義して、それに対して` <*> ` を使ってみます。
316
+ 「2つ以上」と書いたとおり、もちろん3つ以上の引数を受け取る関数に対しても` <*> ` は使えます。例えば、今回の課題で定義しておくと便利であろう、「元金と金利(単位はパーセント)と年数を受け取って、年数後の元金を返す」関数を定義して、それに対して` <*> ` を使ってみます。
328
317
329
- ```
318
+ ``` haskell
330
319
-- Ref: https://support.microsoft.com/ja-jp/help/141695/xl-how-to-calculate-compound-interest
331
320
yearlyRate :: Double -> Double -> Integer -> Double
332
321
yearlyRate principal interestRate years =
333
322
principal * (1 + interestRate / 100 ) ^ years
334
323
```
335
324
336
- 試してましょう。
325
+ 試してましょう。` IO ` 型の値を用意するのに先程の ` returnDoubler ` のような関数を都度定義するのも面倒なので、 ` TypeApplications ` を使って手っ取り早く ` return @IO ` で ` IO ` 型の値を作ります [ ^ return ] :
337
326
338
- ```
339
- ghci> :set -XTypeApplications
327
+ [ ^ return ] : 単なる` return ` だと、ほかの` Monad ` 型クラスのインスタンスである型の` return ` が採用される恐れがあります。` TypeApplications ` を使って` return @IO ` と書けば、「この` return ` は必ず` IO ` に対する` return ` だよ」と明記できるのでこの問題を回避できるのです。
328
+
329
+ ``` haskell
340
330
ghci> yearlyRate <$> return @ IO 100.0 <*> return @ IO 5.0 <*> return @ IO 2
341
331
110.25
342
332
```
343
333
344
- できました!
345
- 3つめの引数を渡すときも` <*> ` を使って残りの命令を渡すだけです。これは4つめ以降の引数でも変わりません。
346
- 途中の式がどのように型付けされているかは自分で確かめてみてください。
334
+ できました!
347
335
348
- ちなみに、「適当な` IO ` 型の値を用意したい、でもいちいち考えるのが面倒くさい」と言うときは、上記のように、言語拡張` TypeApplications ` を有効にした上で` return @IO ` を使うと簡単です。
349
- (単なる` return ` だと、ほかの` Monad ` 型クラスのインスタンスである型の` return ` が採用される恐れがあります。` TypeApplications ` を使って` return @IO ` と書けば、「この` return ` は必ず` IO ` に対する` return ` だよ」と明記できるのでこの問題を回避できるのです)
336
+ 3つめの引数を渡すときも、` <*> ` を使って残りの命令を渡すだけです。4つめ以降の引数でも変わりません。途中の式がどのように型付けされているかは、自分で確かめてみてください。
350
337
351
- それから、上記の例は下記のように、関数を定義しないで直接各種演算子に対して` <$> ` や` <*> ` を使うことによっても実現できます。
352
- ただ、ご覧の通り前置記法で二項演算子を何重も書くのはさすがにつらいので、この例ではやめておいた方がいいでしょう。
338
+ それから、上記の例は下記のように、関数を定義しないで直接それぞれの演算子に対して` <$> ` や` <*> ` を使うというやり方でも実現できます。ただ、ご覧の通り前置記法で二項演算子を何重も書くのはさすがにつらいので、普段はやめておいた方がいいでしょう:
353
339
354
- ```
355
- ghci> (*) <$> return 100.0 <*> ((^) <$> ((1 +) <$> ((/ 100) <$> return 5.0)) <*> return 2)
340
+ ``` haskell
341
+ ghci> (*) <$> return @ IO 100.0 <*> ((^) <$> ((1 + ) <$> ((/ 100 ) <$> return @ IO 5.0 )) <*> return @ IO 2 )
356
342
```
357
343
358
- あるいは、ラムダ抽象を使うのも一つの手です。
344
+ あるいは、ラムダ抽象を使うのも一つの手です(相変わらず一行で書くには読みづらいでしょうが):
359
345
360
- ```
361
- ghci> (\principal interestRate years -> principal * (1 + interestRate / 100.0) ^ years) <$> return 100 <*> return 5.0 <*> return 2
346
+ ``` haskell
347
+ ghci> (\ principal interestRate years -> principal * (1 + interestRate / 100.0 ) ^ years) <$> return @ IO 100 <*> return @ IO 5.0 <*> return @ IO 2
362
348
110.25
363
349
```
364
350
365
- もっと冗長だけどわかりやすいやり方、すなわち` do ` 記法を使ったやり方に立ち返って、
351
+ もっと冗長だけどわかりやすいやり方、すなわち` do ` 記法を使ったやり方に立ち返ってもよいでしょう:
366
352
367
- ```
353
+ ``` haskell
368
354
ghci> : {
369
355
ghci| do
370
- ghci| principal <- return 100.0
371
- ghci| interestRate <- return 5.0
372
- ghci| years <- return 2
373
- ghci| return $ principal * (1 + interestRate / 100) ^ years
356
+ ghci| principal <- return @ IO 100.0
357
+ ghci| interestRate <- return @ IO 5.0
358
+ ghci| years <- return @ IO 2
359
+ ghci| return @ IO $ principal * (1 + interestRate / 100 ) ^ years
374
360
ghci| : }
375
361
110.25
376
362
```
377
363
378
- と書いても、できあがる「命令」の処理内容は全く変わりません。
379
-
380
- これらの` do ` や` <$> ` ・` <*> ` などとの使い分けは、ソースコードの見た目が変わる以外の違いに、ほとんど関係がありません(` IO ` 以外の型の扱いやGHCの` Strict ` という言語拡張を使った場合など、いろいろ例外はありますが割愛します)。
381
- 適宜読みやすいと思う書き方を選んでください。個人的には、迷ったらより冗長な方にするのをおすすめします。
364
+ これらの` do ` や` <$> ` 、` <*> ` などを使い分けることは、ソースコードの見た目を変える以外にほとんど意味がありません(` IO ` 型以外の場合や、GHCの` Strict ` という言語拡張を使った場合など、いろいろ例外はありますが割愛します)。上記のように` do ` を使って書いても、できあがる「命令」の処理内容は変わらないのです。「` <$> ` や` <*> ` で簡潔に書けるけど、簡潔すぎて読みづらいな」と感じたら迷わず` do ` 記法を使って書き直してください。
382
365
383
366
#### ` <$> ` はなぜ引数が2つ以上の場合には使えないのか
384
367
385
- 「後述する」と言って積み残した課題がありました。
386
- 試しに` <$> ` を引数が2つ以上の関数に対して使ってみて、型エラーになることを確認してみましょう。
368
+ 「後述します」と言って積み残した課題がありました。試しに` <$> ` を引数が2つ以上の関数に対して使ってみて、型エラーになることを確認してみましょう:
387
369
388
- ```
370
+ ``` haskell
389
371
ghci> (++) <$> getLine <$> getLine
390
372
391
373
< interactive>: 16 : 1 : error :
0 commit comments