함수 체이닝을 다루기 이전에 먼저 제어흐름, 제어 구조에 대하여 알아본다.
함수형 프로그램에서는 데이터와 제어 흐름을 추상화하여
고수준 컴포넌트사이의 단순 연결(Chaininng)로 취급하기 때문이다.
Control Structure(제어구조)
1960년대에 많은 조사 끝에 플로우차트로 그릴 수 있는 모든 알고리즘들이 two-way selection(if,else)과 pretest logical loop 이 두 가지로 코딩될 수 있다고 알려졌다. 따라서 프로그래밍에서 이 두가지는 매우 중요하다 할 수 있겠다.
물론 two-way selection(if, else) 외에도 switcch case이나 혹은 if 안에 또 if를 사용하는 nested loop 등 여러 selection 등이 있지만 two-way selection은 아주 최소의 것을 말한 것이다.
또한 loop의 종류도 아주 다양하다.
대표적인 것이 for( [ expr_1]; [expr_2]; [expr_3] )과 같은 Counter-Conrolled Loops가 있고
while문과 같이 특정 조건을 만족 시키면 loop를 도는 Logically-Controlled Loops,
break, continue 등과 같이 사용자가 원할 때 Loop를 빠져나올 수 있는 User-Located Loop Control도 있다.
또한 언어에 따라 선택한 iterable 자료구조 안에서 루프를 도는 함수(iterator)를 지정하여 대신 돌게 할 수도 있다.
대표적인 것이 Python의 Generator이다.
def flatten(lst):
for item in lst:
if isinstance(item, list): # check if the item is list
# for subitem in flatten(item):
# yield subitem;
yield from flatten(item)
else:
yield item
data = [ 1, [2, [[[4]]], [0, 5], [], 3], [4], 2, 7
sum = 0
for e in flatten(data):
print(e)
sum +== e
if sum > 10:
break
print('Result:', sum)
https://docs.python.org/3/whatsnew/3.3.html#pep-380
What’s New In Python 3.3 — Python 3.9.0 documentation
contextlib ExitStack now provides a solid foundation for programmatic manipulation of context managers and similar cleanup functionality. Unlike the previous contextlib.nested API (which was deprecated and removed), the new API is designed to work correctl
docs.python.org
좀 더 자세한 설명은 여기서 찾아볼 수 있다.
자바스크립트에서도 앞서 이야기한 루프를 도는 기본적인 방법들(for, while 등)이 있지만 특히 배열의 경우에는 여러 방법들이 있다.
//2. Looping
const fruits = ["🍎", "🍌"];
// a. for
for(let i = 0; i < fruits.length; i++){
console.log(fruits[i])
}
// b. for of
for (let fruit of fruits) {
console.log(fruit);
}
// c. forEach
fruits.forEach((fruit, index) => console.log(fruit, index));
함수 체이닝
OOP 패턴에는 여러 메서드를 단일 구문으로 호출하는 메서드 체이닝이 있다.
상속을 통해 코드를 재사용하면서 용도에 맞게 여러 클래스를 만들어나가며 메서드 체이닝을 사용한다.
class A {
private int a;
private float b;
A()
{
System.out.println("Calling The Constructor");
}
public A setint(int a)
{
this.a = a;
return this;
}
public A setfloat(float b)
{
this.b = b;
return this;
}
void display()
{
System.out.println("Display="
+ a + " " + b);
}
}
// Driver code
public class Example {
public static void main(String[] args)
{
// This is the "method chaining".
new A().setint(10).setfloat(20).display();
}
}
출처 : www.geeksforgeeks.org/method-chaining-in-java-with-examples/
그러나 함수형 프로그래밍에서는 자료구조보다 연산에 더 중점을 두기 때문에
새로운 자료구조, 클래스를 만드는 것이 아니라 고계 연산을 적용하여 일을 한다.
*고계함수: 함수를 일반 객체처럼 인수로 전달하거나 함수로 반환받는 연산
이를 자바스크립트에서는 함수 체이닝이라고 하며 함수를 인수를 받으며, 기존의 수동루프를 대체하게 된다.
로대쉬JS 라이브러리를 사용하여 번잡한 수동루프를 처리하는 방식으로 이루어지기 때문이다.
1. 루프처리, 분기문
let enrollment = [
{enrolled: 2, grade :100},
{enrolled: 2, grade :80},
{enrolled: 1, grade :89},
];
var totalGrades = 0;
var totalStudentsFound = 0;
for(let i = 0; i < enrollemeent.length; i++){
let student = enrollment[i];
if(student != null){
if(student.enrolled > 1){
totalGrades += student.grade;
totalStudentsFound++;
}
}
}
var average = totalGrades / totalStudentsFound ;
2. 함수 체인으로 프로그래밍
let enrollment = [
{enrolled: 2, grade :100},
{enrolled: 2, grade :80},
{enrolled: 1, grade :89},
];
enrollment
.filter((student) => student.enrolled > 1)
.map((student) => student.grade)
.reduce((prev, cur) => prev + cur) / enrollment.length
filter, map, reduce안에 들어있는 함수를 CallBack함수라고 한다. CallBack 함수는 말 그대로 '다시 부르는 함수'로 함수가 생성될 때는 실행되지 않다가 나중에 호출 될 때 실행되는 함수이다.
배열을 다룰 때 자바스크립트에서 사용할 수 있는 고계함수들은 이보다 더 많은데 이는 아래에서 확인할 수 있다. 정확한 사용방법을 보고 싶다면 에디터에서 함수를 호출할 때 인자와 반환 타입들을 확인할 수 있고 혹은 MDN 등에서 확인해볼 수도 있다.
나의 경우 함수형 자바스크립트 책과 드림코딩 엘리님 수업을 참고하였다.
이 수업에서 총 10문제가 나오는데 my answer이라고 적힌 것은 내가 푼 답이고 tearcher's는 수업에서 보여준 정답이다.
// 01. make a string out of an array
{
const fruits = ["apple", "banana", "orange"];
//my answer
console.log(fruits.reduce((prev, cur) => prev + cur));
//tearher's
console.log(fruits.join());
//can add seperator in join
}
// 02. make an aray out of a stirng
{
const fruits = "🍎,🍉,🍑,🍅";
console.log(fruits.split(","));
//seperater --necessary
//limits -- optional
console.log(fruits.split(",", 2));
}
// 03. make this array look like this [5,4,3,2,1]
{
const array = [1, 2, 3, 4, 5];
array.reverse();
}
// 04. make new array without the first two elements
{
const array = [1, 2, 3, 4, 5];
console.log(array.slice(2, 5));
console.log(array);
// change the original array
const array2 = [1, 2, 3, 4, 5];
console.log(array2.splice(2, 5));
console.log(array2);
}
class Student {
constructor(name, age, enrolled, score) {
this.name = name;
this.age = age;
this.enrolled = enrolled;
this.score = score;
}
}
const students = [
new Student("A", 29, true, 45),
new Student("B", 28, false, 80),
new Student("C", 30, true, 90),
new Student("D", 40, false, 66),
new Student("E", 18, true, 88)
];
// 05.find a student with the score 90
{
// my answer
const score90 = (arr) => arr.score === 90;
const getname = (arr) => arr.name;
console.log(students.filter(score90).map(getname));
//teacher's answer
console.log(students.find(score90).name);
}
// 06. make an array of enrolled students
{
// my answer
const ifenrolled = (arr) => arr.enrolled === true;
const getname = (arr) => arr.name;
console.log(students.filter(ifenrolled).map(getname));
}
// 07. make an array containing only the students' scores
// result should be: [45, 80, 90, 66, 88]
{
const getscore = (arr) => arr.score;
console.log(students.map(getscore));
}
// 08. check if there is a student with the score lower than 50
{
const iflowerthan50 = (arr) => arr.score < 50;
console.log(students.some(iflowerthan50));
const result = !students.every((student) => student.score >= 50);
console.log(result);
}
//09. compute students' average score
{
const getscore = (arr) => arr.score;
console.log(
students.map(getscore).reduce((prev, cur) => prev + cur) / students.length
);
}
// 10. make a string containing all the scores
// result should be: '45, 80, 90, 66, 88'
{
const getscore = (arr) => arr.score;
console.log(students.map(getscore).join());
}
// Bonus do q10 sorted in ascending order
{
const getscore = (arr) => arr.score;
console.log(students.map(getscore).sort((a, b) => a - b));
}
다음 편에는 재귀 호출과 함수 체이닝에 대해서 다루어보겠다.
'javascript' 카테고리의 다른 글
[함수형 언어, 자바스크립트] 비동기 처리 (2) Promise의 이해 (0) | 2020.11.17 |
---|---|
[함수형 언어, 자바스크립트] 비동기 처리 (1) Callback 함수의 이해 (0) | 2020.11.17 |
[함수형 언어, 자바스크립트] 배열 (0) | 2020.10.22 |
함수형 언어, 자바스크립트 (0) | 2020.10.14 |
함수형 언어, 자바스크립트 START (0) | 2020.10.14 |