回答編集履歴

4

誤字の修正

2018/04/22 13:37

投稿

miyabi-sun
miyabi-sun

スコア21158

test CHANGED
@@ -42,7 +42,7 @@
42
42
 
43
43
 
44
44
 
45
- 別にになるケースも殆ど無いですし、
45
+ 別にになるケースも殆ど無いですし、
46
46
 
47
47
  無くてもJavaScriptはチューリング完全ですので使わなくて構いません。
48
48
 

3

ちゃんと質問タイトル通りに修正

2018/04/22 13:36

投稿

miyabi-sun
miyabi-sun

スコア21158

test CHANGED
@@ -1,424 +1,62 @@
1
- 関数型プログラミング的な事をやりたいのですか?
2
-
3
- もしそうなら、まずは関数にconsole.logを使う事をやめてください。
1
+ > 再帰関数を引数取りそれ実行する高階関数のコンテキストを変数巻き上げを使わずに変える方法
4
-
5
- 値を返さない関数は、函数ではなくサブルーチンです。
6
2
 
7
3
 
8
4
 
9
- 関数型プログラミングは関数を使って引数から入った値を戻り値として受け取る形で値を加工します。
10
-
11
- この関数をパーツ片として、レゴを組み立てるように構築るから関数型なのです
5
+ タイトルどおりに回答していきます。
12
6
 
13
7
 
14
8
 
15
- console.log典型的なサブルーチンであり、
9
+ 質問文のコードあくま参考資料であり、
16
10
 
17
- 値を返さず標準出力へ文字列を出力するので計算途中に組み込む事は出来ません
11
+ 例えば記述してあ関数は関数として要件を満たしていませんので、
18
12
 
19
- 基本的は最後最後で使う設計にしましょう
13
+ 一旦ノイズということでわき追いやって、タイトル集中て考えていき
20
14
 
21
15
 
22
16
 
23
- ---
17
+ > 再帰関数を引数に取り
24
18
 
25
19
 
26
20
 
21
+ 再帰関数はそれ自体が関数なので、引数に取った高階関数は用意すること自体は可能です。
22
+
27
- 次に再帰関数ループの戦略を考えていきます。
23
+ 再帰関数はそれ自体がループのような性質であり、
24
+
25
+ 間に処理を挟みたいという利用用途やケースがちょっと分かりづらいです。
28
26
 
29
27
 
30
28
 
31
- 再帰関数は間に処理挟めません。
29
+ むしろ再帰関数自体公開関数であるべきで、
32
30
 
33
- for文をラッピングした関数を用意して、
34
-
35
- 「いやー、このfor文の毎回の処理自作処理を差し込みたいんだよね」って言ってるようものです。
31
+ 値を加工する関数を引数とり受け付けるが一般的プログラミングです。
36
32
 
37
33
 
38
34
 
39
- こうなってしまっては間に何もやりたい事を挟めないので、
40
-
41
- 「ループさせない」ようしてください。
35
+ > 変数巻き上げを使わず
42
-
43
- 再帰関数も同様で、やりたい事が完成するまでループさせないで下さい。
44
36
 
45
37
 
46
38
 
47
- てこれが細分化され理想的な関の形です。
39
+ 変数巻き上げって同じスコープの下の行で宣言したが、
48
40
 
49
- 入力値があり、戻り値がある立派な関数です。
50
-
51
- っとアレ事を言えば副作用もく参照透過でもある理想的な挙動をしま
41
+ 上の行でundefined扱いで取れてしまう意図どおりにい変な挙動よね?
52
42
 
53
43
 
54
44
 
55
- ```JavaScript
45
+ 別に特になるケースも殆ど無いですし、
56
46
 
57
- const sharp = n => '#'.repeat(n)
58
-
59
- console.log(func(5)) // #####
47
+ 無くてもJavaScriptはチューリング完全ですので使わなくて構いません。
60
-
61
- ```
62
48
 
63
49
 
64
50
 
65
- 次に新しい機能として罫線とシャープの組み合わせの関数を考えていきます。
66
-
67
- 罫線を返すhr関数です。
51
+ > 高階関数のコンテキスト
68
52
 
69
53
 
70
54
 
71
- ```JavaScript
55
+ 変えたい対象は文脈から推測するに、
72
56
 
73
- const hr = () => '-----'
57
+ 再帰関数のコンテキストではなく、高階関数のコンテキストですよね?
74
58
 
75
- console.log(hr()) // -----
76
-
77
- ```
78
-
79
-
80
-
81
- ではこの2つの関数を合成させましょう。
82
-
83
- 罫線とシャープを間髪いれずに返すhrAndSharpです(ネーミングセンス皆無)
84
-
85
-
86
-
87
- ```JavaScript
88
-
89
- const sharp = n => '#'.repeat(n)
90
-
91
- const hr = () => '-----'
92
-
93
- const hrAndSharp = ((sharp, hr) =>
94
-
95
- num => [hr(), sharp(num)]
96
-
97
- )(sharp, hr)
98
-
99
- console.log(hrAndSharp(3)) // ["-----", "###"]
100
-
101
-
102
-
103
- console.log([1, 2, 3, 4, 5].map(hrAndSharp))
104
-
105
- // [
106
-
107
- // ["-----", "#"],
108
-
109
- // ["-----", "##"],
110
-
111
- // ["-----", "###"],
112
-
113
- // ["-----", "####"],
114
-
115
- // ["-----", "#####"]
116
-
117
- // ]
118
-
119
- ```
120
-
121
-
122
-
123
- 5, 4, 3, 2, 1というのは階乗(factorial)というそうですから、
124
-
125
- そんな感じの関数をさくっと用意して…
126
-
127
-
128
-
129
- ```JavaScript
130
-
131
- const factorial = (num, result = []) => {
132
-
133
- if (num <= 0) return result
134
-
135
- result.push(num)
136
-
137
- return factorial(num - 1, result)
138
-
139
- }
140
-
141
- console.log(factorial(5)) // [5, 4, 3, 2, 1]
142
-
143
-
144
-
145
- const sharp = n => '#'.repeat(n)
146
-
147
- const hr = () => '-----'
148
-
149
- const hrAndSharp = ((sharp, hr) =>
150
-
151
- num => [hr(), sharp(num)]
152
-
153
- )(sharp, hr)
154
-
155
-
156
-
157
- console.log(factorial(5).map(hrAndSharp))
158
-
159
- // [
160
-
161
- // ["-----", "#####"],
162
-
163
- // ["-----", "####"],
164
-
165
- // ["-----", "###"],
166
-
167
- // ["-----", "##"],
168
-
169
- // ["-----", "#"]
170
-
171
- // ]
172
-
173
- ```
174
-
175
-
176
-
177
- ここまでいけばあと一息ですね。
178
-
179
-
180
-
181
- - 2次元配列を1次元配列にする
182
-
183
- - 最後に罫線を追加
184
-
185
- - まとめて出力
186
-
187
-
188
-
189
- 2次元配列を1次元配列にするのはfor文や再帰関数でもいけますが、
190
-
191
- reduceを使えば一撃です。
192
-
193
-
194
-
195
- ```JavaScript
196
-
197
- // reduceを使って2次元配列を1次元配列に修正してみた
198
-
199
- const result = factorial(5).map(hrAndSharp).reduce((arr, it) => {
200
-
201
- it.forEach(_ => arr.push(_))
202
-
203
- return arr
204
-
205
- }, [])
206
-
207
- console.log(result)
208
-
209
- // ["-----", "#####", "-----", "####", "-----", "###", "-----", "##", "-----", "#"]
210
-
211
-
212
-
213
- // 出力用関数をおもむろに準備
214
-
215
- const output = it => console.log(it)
216
-
217
-
218
-
219
- // newFuncを作るとこうなる
220
-
221
- const newFunc = ((factorial, hrAndSharp) =>
222
-
223
- num => {
224
-
225
- const results = factorial(5).map(hrAndSharp).reduce((arr, it) => {
226
-
227
- it.forEach(_ => arr.push(_))
228
-
229
- return arr
230
-
231
- }, [])
232
-
233
- results.push(hr())
234
-
235
- return results
236
-
237
- }
238
-
239
- )(factorial, hrAndSharp)
240
-
241
- newFunc(5).forEach(output)
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
- const func = ((factorial, sharp) =>
270
-
271
- num => factorial(5).map(sharp)
272
-
273
- )(factorial, sharp)
274
-
275
- func(5).forEach(output)
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
- まぁ高階関数ご大層用意がも、
59
+ 高階関数は今ら作るものので、お好きように変え下さい。
312
-
313
- JSの標準で用意されている高階関数的なメソッドチェーンで実現できます。
314
-
315
-
316
-
317
- ```JavaScript
318
-
319
- const result = Array(5)
320
-
321
- .fill(0)
322
-
323
- .map((_, i) => ['-----', '#'.repeat(5 - i)])
324
-
325
- .reduce((arr, it) => {
326
-
327
- it.forEach(_ => arr.push(_))
328
-
329
- return arr
330
-
331
- }, [])
332
-
333
- result.push('-----')
334
-
335
-
336
-
337
- console.log(result)
338
-
339
- // ["-----", "#####", "-----", "####", "-----", "###", "-----", "##", "-----", "#", "-----"]
340
-
341
-
342
-
343
- result.forEach(it => console.log(it))
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
- もし私ならコードの再利用云々以前にこれを関数に包めて`newFunc`完成です。
372
-
373
- この程度の分量なら細分化以前に必要になる度に書いてしまっても良いかなぁと思います。
374
-
375
-
376
-
377
- 因みに`func`の作り方はこれを使えばワンライナーです。
378
-
379
-
380
-
381
- ```JavaScript
382
-
383
- const result = Array(5)
384
-
385
- .fill(0)
386
-
387
- .map((_, i) => '#'.repeat(5 - i))
388
-
389
- // ["#####", "####", "###", "##", "#"]
390
-
391
- ```
392
-
393
-
394
-
395
- ---
396
-
397
-
398
-
399
- おまけ: 出力する歳のイディオム
400
-
401
-
402
-
403
- JavaScriptではつかえませんが、
404
-
405
- Node.jsでは`¥n`が改行になります。
406
-
407
- なので配列は`arr.join('¥n')`で文字列に加工してしまって一気に吐き出すと、
408
-
409
- パフォーマンス的にもかなり良くなり、普通にconsole.logを書きまくるよりも速度が上がります。
410
-
411
-
412
-
413
- ```JavaScript
414
-
415
- const result = ["-----", "#####", "-----", "####", "-----", "###", "-----", "##", "-----", "#", "-----"]
416
-
417
- console.log(result.join('¥n'))
418
-
419
- // -----¥n#####¥n-----¥n####¥n-----¥n###¥n-----¥n##¥n-----¥n#¥n-----
420
-
421
- ```
422
60
 
423
61
 
424
62
 
@@ -430,28 +68,16 @@
430
68
 
431
69
 
432
70
 
433
- 実際関数型プログラミングが綺麗らしいと言われますが、
434
-
435
- 動けば何でもいい、ードの綺麗さなど知ったことかという人の多くはC系統の命令型プログラミ好みますので、
71
+ > 再帰関数を引数に取りそれを実行する高階関数のコンテキスト変数巻き上げを使わずに変える方法
436
-
437
- 関数型プログラミングの世界に入ってこないだけの話です。
438
72
 
439
73
 
440
74
 
441
- 命令型やってた人間が、ソースの可読性をこだわりぬいた結果、
75
+ 「再帰関数を引数に取り」 → 誰も作れる
442
76
 
443
- 関数型プログラミグに活路見出し門戸を叩くケスも結構多いと聞きます。
77
+ 「それを実行する高階関数のコテキスト変える」 → JavaScriptはチュリング完全なので可能
78
+
79
+ 「変数巻き上げを使わず」 → むしろJavaScriptのダメな挙動なので使わない方が良い、もちろん可能
444
80
 
445
81
 
446
82
 
447
- 例え関数型プログラミングを軸にしたとしても、汚い設計やコードは簡単につくれます。
448
-
449
- 関数型プログラミングが綺麗というのは、キレイなコードを書くために試行錯誤した前人達の努力の結晶なんですね。
450
-
451
-
452
-
453
- 今回の回答文では質問文からやりたい事を満たす為のパーツ片の紹介という感じで書きました。
454
-
455
- おまけまで含めてもまだまだ考える余地は沢山あるかと思いますので、
456
-
457
- 色々と試行錯誤しキレイな形というのを模索しみて下さい
83
+ ての条件論理積で考えた場合、全可能なので可能です

2

考え方のフローを記述するよう変更

2018/04/22 13:36

投稿

miyabi-sun
miyabi-sun

スコア21158

test CHANGED
@@ -6,19 +6,17 @@
6
6
 
7
7
 
8
8
 
9
- サブルーチンは当然ながら値を返さないので更なる工夫が出来ません。
10
-
11
- 関数型プログラミングは細かい関数のパーツ片同士レゴのように組み合わせ機能完成させ手法です。
9
+ 関数型プログラミングは関数を使っ引数から入った値戻り値として受け取値を加工します。
12
-
10
+
13
- 従って値返さず、他のパーツと組み合わせ辛いサブルーチンは締め以外は使えません
11
+ この関数をパーツして、レゴを組み立てるように構築するから関数型なの
14
-
15
-
16
-
12
+
13
+
14
+
17
- console.logは値を出力する処理、つまりサブルーチンです。
15
+ console.logは典型的なサブルーチンであり、
18
-
16
+
19
- ので何かとセットで使う事は難しいのです
17
+ 値を返さず標準出力へ文字列を出力するので計算途中に組み込む事は出来ません
20
-
18
+
21
- 基本的には最後の最後で使う設計にしてください
19
+ 基本的には最後の最後で使う設計にしましょう
22
20
 
23
21
 
24
22
 
@@ -26,29 +24,279 @@
26
24
 
27
25
 
28
26
 
27
+ 次に再帰関数やループの戦略を考えていきます。
28
+
29
+
30
+
29
- 次に再帰関数は間に処理が挟めません。
31
+ 再帰関数は間に処理が挟めません。
30
-
31
-
32
32
 
33
33
  for文をラッピングした関数を用意して、
34
34
 
35
- 「いやー、このfor文の毎回の処理に自作の処理を差し込みたいんだよね」って言ってるようなものです。
36
-
37
-
38
-
39
- 間に処理を挟む事は出来ませんが代替案はあります。
40
-
41
- 分かりやすいように一つ手段を挙げるなら、
42
-
43
- 予め`###`の詰った配列を返させた後に、その配列を加工してくとう手段でしょう
44
-
45
-
46
-
47
- だけ高階関数に出来なくもありませんが、
48
-
49
- それは高階関数と呼べるものかは怪しいものです。
50
-
51
- (詳しはおまけを参照してください)
35
+ 「いやー、このfor文の毎回の処理に自作の処理を差し込みたいんだよね」って言ってるようなものです。
36
+
37
+
38
+
39
+ こうなってしまっては間に何もやりたい事を挟めないので、
40
+
41
+ 「ループさせなようにしてください。
42
+
43
+ 再帰関数も同様で、やりたい事が完成するでループさせで下さい。
44
+
45
+
46
+
47
+ そしが細分化された理想的な関数の形です。
48
+
49
+ 入力値があり、戻り値がある立派な関数です。
50
+
51
+ (もっとアレな事を言えば副作用もなく参照透過でもある理想的な挙動をます)
52
+
53
+
54
+
55
+ ```JavaScript
56
+
57
+ const sharp = n => '#'.repeat(n)
58
+
59
+ console.log(func(5)) // #####
60
+
61
+ ```
62
+
63
+
64
+
65
+ 次に新しい機能として罫線とシャープの組み合わせの関数を考えていきます。
66
+
67
+ 罫線を返すhr関数です。
68
+
69
+
70
+
71
+ ```JavaScript
72
+
73
+ const hr = () => '-----'
74
+
75
+ console.log(hr()) // -----
76
+
77
+ ```
78
+
79
+
80
+
81
+ ではこの2つの関数を合成させましょう。
82
+
83
+ 罫線とシャープを間髪いれずに返すhrAndSharpです(ネーミングセンス皆無)
84
+
85
+
86
+
87
+ ```JavaScript
88
+
89
+ const sharp = n => '#'.repeat(n)
90
+
91
+ const hr = () => '-----'
92
+
93
+ const hrAndSharp = ((sharp, hr) =>
94
+
95
+ num => [hr(), sharp(num)]
96
+
97
+ )(sharp, hr)
98
+
99
+ console.log(hrAndSharp(3)) // ["-----", "###"]
100
+
101
+
102
+
103
+ console.log([1, 2, 3, 4, 5].map(hrAndSharp))
104
+
105
+ // [
106
+
107
+ // ["-----", "#"],
108
+
109
+ // ["-----", "##"],
110
+
111
+ // ["-----", "###"],
112
+
113
+ // ["-----", "####"],
114
+
115
+ // ["-----", "#####"]
116
+
117
+ // ]
118
+
119
+ ```
120
+
121
+
122
+
123
+ 5, 4, 3, 2, 1というのは階乗(factorial)というそうですから、
124
+
125
+ そんな感じの関数をさくっと用意して…
126
+
127
+
128
+
129
+ ```JavaScript
130
+
131
+ const factorial = (num, result = []) => {
132
+
133
+ if (num <= 0) return result
134
+
135
+ result.push(num)
136
+
137
+ return factorial(num - 1, result)
138
+
139
+ }
140
+
141
+ console.log(factorial(5)) // [5, 4, 3, 2, 1]
142
+
143
+
144
+
145
+ const sharp = n => '#'.repeat(n)
146
+
147
+ const hr = () => '-----'
148
+
149
+ const hrAndSharp = ((sharp, hr) =>
150
+
151
+ num => [hr(), sharp(num)]
152
+
153
+ )(sharp, hr)
154
+
155
+
156
+
157
+ console.log(factorial(5).map(hrAndSharp))
158
+
159
+ // [
160
+
161
+ // ["-----", "#####"],
162
+
163
+ // ["-----", "####"],
164
+
165
+ // ["-----", "###"],
166
+
167
+ // ["-----", "##"],
168
+
169
+ // ["-----", "#"]
170
+
171
+ // ]
172
+
173
+ ```
174
+
175
+
176
+
177
+ ここまでいけばあと一息ですね。
178
+
179
+
180
+
181
+ - 2次元配列を1次元配列にする
182
+
183
+ - 最後に罫線を追加
184
+
185
+ - まとめて出力
186
+
187
+
188
+
189
+ 2次元配列を1次元配列にするのはfor文や再帰関数でもいけますが、
190
+
191
+ reduceを使えば一撃です。
192
+
193
+
194
+
195
+ ```JavaScript
196
+
197
+ // reduceを使って2次元配列を1次元配列に修正してみた
198
+
199
+ const result = factorial(5).map(hrAndSharp).reduce((arr, it) => {
200
+
201
+ it.forEach(_ => arr.push(_))
202
+
203
+ return arr
204
+
205
+ }, [])
206
+
207
+ console.log(result)
208
+
209
+ // ["-----", "#####", "-----", "####", "-----", "###", "-----", "##", "-----", "#"]
210
+
211
+
212
+
213
+ // 出力用関数をおもむろに準備
214
+
215
+ const output = it => console.log(it)
216
+
217
+
218
+
219
+ // newFuncを作るとこうなる
220
+
221
+ const newFunc = ((factorial, hrAndSharp) =>
222
+
223
+ num => {
224
+
225
+ const results = factorial(5).map(hrAndSharp).reduce((arr, it) => {
226
+
227
+ it.forEach(_ => arr.push(_))
228
+
229
+ return arr
230
+
231
+ }, [])
232
+
233
+ results.push(hr())
234
+
235
+ return results
236
+
237
+ }
238
+
239
+ )(factorial, hrAndSharp)
240
+
241
+ newFunc(5).forEach(output)
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
+ const func = ((factorial, sharp) =>
270
+
271
+ num => factorial(5).map(sharp)
272
+
273
+ )(factorial, sharp)
274
+
275
+ func(5).forEach(output)
276
+
277
+ // #####
278
+
279
+ // ####
280
+
281
+ // ###
282
+
283
+ // ##
284
+
285
+ // #
286
+
287
+ ```
288
+
289
+
290
+
291
+ まぁ、細部は色々ありますが、しっかりパーツ片単位に分解していくとこんな感じがゴールになるかと思います。
292
+
293
+
294
+
295
+ ん?関数作りすぎじゃない?そうかもしれませんね。
296
+
297
+ 再利用するまでもないようなものは、
298
+
299
+ どんどんアロー関数化したりしてくっつけていっても良いかと思います。
52
300
 
53
301
 
54
302
 
@@ -56,120 +304,90 @@
56
304
 
57
305
 
58
306
 
59
- さて、実際にコード書いていきます。
60
-
61
-
62
-
63
- JavaScriptは配列の加工がわりです。
64
-
65
- ですので配列を返す関数を作るようにしてください
66
-
67
- これがスタートラインです。
68
-
69
-
70
-
71
- ※面倒なのでES6で書きますが、アロー関数と変数宣言以外はES5のものを利用していますので移植は楽だと思います。
72
-
73
- ※JSの`array.push`は破壊的なメソッドなので関数としては欠陥品なのですが、JSで毎回新しく配列を作るとパフォーマンス的な影響がデカイ為、再帰関数の最初の発火時には初期値として`[]`を新しく作る思想で書いて妥協しています。
74
-
75
-
76
-
77
- ```JavaScript
78
-
79
- const output = it => console.log(it)
80
-
81
- const func = (n, arr = []) => {
82
-
83
- if (n <= 0) return arr
84
-
85
- arr.push('#'.repeat(n))
86
-
87
- return func(n - 1, arr)
88
-
89
- }
90
-
91
-
92
-
93
- console.log(func(5))
307
+ おまけ: 配列操作使う
308
+
309
+
310
+
311
+ まぁ高階関数かご大層な用がなくても、
312
+
313
+ JS標準用意されている高階関数的なメソッドチェーンで実現できます
314
+
315
+
316
+
317
+ ```JavaScript
318
+
319
+ const result = Array(5)
320
+
321
+ .fill(0)
322
+
323
+ .map((_, i) => ['-----', '#'.repeat(5 - i)])
324
+
325
+ .reduce((arr, it) => {
326
+
327
+ it.forEach(_ => arr.push(_))
328
+
329
+ return arr
330
+
331
+ }, [])
332
+
333
+ result.push('-----')
334
+
335
+
336
+
337
+ console.log(result)
338
+
339
+ // ["-----", "#####", "-----", "####", "-----", "###", "-----", "##", "-----", "#", "-----"]
340
+
341
+
342
+
343
+ result.forEach(it => console.log(it))
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
+ もし私ならコードの再利用云々以前にこれを関数に包めて`newFunc`完成です。
372
+
373
+ この程度の分量なら細分化以前に必要になる度に書いてしまっても良いかなぁと思います。
374
+
375
+
376
+
377
+ 因みに`func`の作り方はこれを使えばワンライナーです。
378
+
379
+
380
+
381
+ ```JavaScript
382
+
383
+ const result = Array(5)
384
+
385
+ .fill(0)
386
+
387
+ .map((_, i) => '#'.repeat(5 - i))
94
388
 
95
389
  // ["#####", "####", "###", "##", "#"]
96
390
 
97
- func(5).forEach(output)
98
-
99
- // #####
100
-
101
- // ####
102
-
103
- // ###
104
-
105
- // ##
106
-
107
- // #
108
-
109
- ```
110
-
111
-
112
-
113
- 次、配列を取る関数として作りましょう。
114
-
115
-
116
-
117
- ```JavaScript
118
-
119
- const output = it => console.log(it)
120
-
121
- const func = (n, arr = []) => {
122
-
123
- if (n <= 0) return arr
124
-
125
- arr.push('#'.repeat(n))
126
-
127
- return func(n - 1, arr)
128
-
129
- }
130
-
131
- const newFunc = (hr, arr, result = []) => {
132
-
133
- result.push(hr)
134
-
135
- if (arr.length === 0) return result
136
-
137
- result.push(arr[0])
138
-
139
- return newFunc(hr, arr.slice(1), result)
140
-
141
- }
142
-
143
-
144
-
145
- console.log(newFunc('-----', func(5)))
146
-
147
- // ["-----", "#####", "-----", "####", "-----", "###", "-----", "##", "-----", "#", "-----"]
148
-
149
- newFunc('-----', func(5)).forEach(output)
150
-
151
- // -----
152
-
153
- // #####
154
-
155
- // -----
156
-
157
- // ####
158
-
159
- // -----
160
-
161
- // ###
162
-
163
- // -----
164
-
165
- // ##
166
-
167
- // -----
168
-
169
- // #
170
-
171
- // -----
172
-
173
391
  ```
174
392
 
175
393
 
@@ -178,65 +396,27 @@
178
396
 
179
397
 
180
398
 
181
- おまけ 高階関数を使う
399
+ おまけ: 出力する歳のイディオム
400
+
401
+
402
+
182
-
403
+ JavaScriptではつかえませんが、
183
-
184
-
404
+
185
- 初期のfunc関数を配列を返すようなものではなく、単機能にしぼりましょう
405
+ Node.jsでは`¥n`が改行になりま
406
+
186
-
407
+ なので配列は`arr.join('¥n')`で文字列に加工してしまって一気に吐き出すと、
408
+
187
- ちょっとマートさ欠けします、色々と改良できそうではあります。
409
+ パフォーマンもかなり良くなり、普通にconsole.logを書きまくよりも速度がります。
188
-
189
-
190
-
410
+
411
+
412
+
191
- ```JavaScript
413
+ ```JavaScript
192
-
193
- const output = it => console.log(it)
414
+
194
-
195
- const hr = () => '-----'
196
-
197
- const func = n => '#'.repeat(n)
198
-
199
- const newFunc = (hr, fn, n, arr = []) => {
200
-
201
- arr.push(hr())
202
-
203
- if (n <= 0) return arr
204
-
205
- arr.push(fn(n))
206
-
207
- return newFunc(hr, fn, n - 1, arr)
208
-
209
- }
210
-
211
-
212
-
213
- console.log(newFunc(hr, func, 5))
214
-
215
- // ["-----", "#####", "-----", "####", "-----", "###", "-----", "##", "-----", "#", "-----"]
415
+ const result = ["-----", "#####", "-----", "####", "-----", "###", "-----", "##", "-----", "#", "-----"]
216
-
416
+
217
- newFunc(hr, func, 5).forEach(output)
417
+ console.log(result.join('¥n'))
218
-
418
+
219
- // -----
419
+ // -----¥n#####¥n-----¥n####¥n-----¥n###¥n-----¥n##¥n-----¥n#¥n-----
220
-
221
- // #####
222
-
223
- // -----
224
-
225
- // ####
226
-
227
- // -----
228
-
229
- // ###
230
-
231
- // -----
232
-
233
- // ##
234
-
235
- // -----
236
-
237
- // #
238
-
239
- // -----
240
420
 
241
421
  ```
242
422
 
@@ -246,121 +426,13 @@
246
426
 
247
427
 
248
428
 
249
- おまけ: 配列操作を使う
250
-
251
-
252
-
253
- まぁ高階関数とかご大層な事しなくても、JSの標準で用意されている高階関数的なメソッドチェーンで実現できます。
254
-
255
-
256
-
257
- ```JavaScript
258
-
259
- const output = it => console.log(it)
260
-
261
- const sharp = n => '#'.repeat(n)
262
-
263
-
264
-
265
- const n = 5
266
-
267
- const result = Array(n)
268
-
269
- .fill(0)
270
-
271
- .map((_, i) => ['-----', sharp(n - i)])
272
-
273
- .reduce((arr, it) => {
274
-
275
- it.forEach(_ => arr.push(_))
276
-
277
- return arr
278
-
279
- }, [])
280
-
281
- result.push('-----')
282
-
283
-
284
-
285
- console.log(result)
286
-
287
- // ["-----", "#####", "-----", "####", "-----", "###", "-----", "##", "-----", "#", "-----"]
288
-
289
- result.forEach(output)
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
- JavaScriptではつかえませんが、
332
-
333
- Node.jsでは`¥n`が改行になります。
334
-
335
- なので配列は`arr.join('¥n')`で文字列に加工してしまって一気に吐き出すと、
336
-
337
- パフォーマンス的にもかなり良くなり、普通にconsole.logを書きまくるよりも速度が上がります。
338
-
339
-
340
-
341
- ```JavaScript
342
-
343
- const result = ["-----", "#####", "-----", "####", "-----", "###", "-----", "##", "-----", "#", "-----"]
344
-
345
- console.log(result.join('¥n'))
346
-
347
- // -----¥n#####¥n-----¥n####¥n-----¥n###¥n-----¥n##¥n-----¥n#¥n-----
348
-
349
- ```
350
-
351
-
352
-
353
- ---
354
-
355
-
356
-
357
429
  まとめ
358
430
 
359
431
 
360
432
 
361
433
  実際関数型プログラミングが綺麗らしいと言われますが、
362
434
 
363
- 動けば何でもいい、コードの綺麗さなど知ったことかという人はC系統の命令型プログラミングを好みますので、
435
+ 動けば何でもいい、コードの綺麗さなど知ったことかという人の多くはC系統の命令型プログラミングを好みますので、
364
436
 
365
437
  関数型プログラミングの世界に入ってこないだけの話です。
366
438
 
@@ -372,14 +444,14 @@
372
444
 
373
445
 
374
446
 
375
- なので例え関数型プログラミングを軸にしたとしても、汚い設計やコードは簡単につくれます。
447
+ 例え関数型プログラミングを軸にしたとしても、汚い設計やコードは簡単につくれます。
376
-
448
+
377
- 関数型プログラミングが綺麗というのは、キレイなコードを書くために試行錯誤した前人達の努力の証だと考えています。
449
+ 関数型プログラミングが綺麗というのは、キレイなコードを書くために試行錯誤した前人達の努力の結晶なんで
378
450
 
379
451
 
380
452
 
381
453
  今回の回答文では質問文からやりたい事を満たす為のパーツ片の紹介という感じで書きました。
382
454
 
383
- おまけまで含めても綺麗に収まる形に収まっていないと思いますので、
455
+ おまけまで含めてもまだまだ考え余地沢山あるかと思いますので、
384
456
 
385
457
  色々と試行錯誤してキレイな形というのを模索してみて下さい。

1

締めの文章追加

2018/04/22 12:54

投稿

miyabi-sun
miyabi-sun

スコア21158

test CHANGED
@@ -360,16 +360,26 @@
360
360
 
361
361
  実際関数型プログラミングが綺麗らしいと言われますが、
362
362
 
363
+ 動けば何でもいい、コードの綺麗さなど知ったことかという人間はC系統の命令型プログラミングを好みますので、
364
+
363
- バカな人間は関数型プログラミングの世界に入ってこないだけの話であり、
365
+ 関数型プログラミングの世界に入ってこないだけの話です。
366
+
367
+
368
+
364
-
369
+ 命令型でやってた人間が、ソースの可読性をこだわりぬいた結果、
370
+
371
+ 関数型プログラミングに活路を見出し門戸を叩くケースも結構多いと聞きます。
372
+
373
+
374
+
365
- 関数型プログラミングを軸にしたとしても、汚い設計やコードは簡単につくれます。
375
+ なので例え関数型プログラミングを軸にしたとしても、汚い設計やコードは簡単につくれます。
376
+
377
+ 関数型プログラミングが綺麗というのは、キレイなコードを書くために試行錯誤した前人達の努力の証だと考えています。
366
378
 
367
379
 
368
380
 
369
381
  今回の回答文では質問文からやりたい事を満たす為のパーツ片の紹介という感じで書きました。
370
382
 
371
-
372
-
373
383
  おまけまで含めても綺麗に収まる形には収まっていないと思いますので、
374
384
 
375
385
  色々と試行錯誤してキレイな形というのを模索してみて下さい。