Skip to content

2016 08 09 kmh

minhee0405 edited this page Aug 16, 2016 · 22 revisions

[함수형 사고] CHAPTER2 전환

함수형 코드를 작성하기 위해서는 문제에 접근하는 방식의 전환이 필요.

2.1 일반적인 예제

함수형 프로그래밍은 복잡한 최적화는 런타임에게 맡기고 개발자가 좀 더 추상화된 수준에서 코드를 작성할수 있게 함으로써, 알고리즘 측면에서 가비지 컬렉션과 동일한 역할을 수행할 것이다. 개발자들은 가비지 컬렉션에서 얻었던 것같이 복잡성이 낮아지고 성능이 높아지는 혜택을 받게 될 것이다.

2.1.1 명령형 처리

명령형 프로그래밍이랑 상태를 변형하는 일련의 명령들로 구성된 프로그래밍 방식
-전형적인 for 루프가 명령형 프로그래밍의 예이다

어떤 이름 목록에서, 한글자로된 이름을 제외한 모든 이름을 대문자화해서 쉽표로 연결한 문자열을 구하는 코드를 생각해보자.
명령형 프로그래밍은 개발자로 하여금 루프 내에서 연산하기를 권장한다.

public class TheCompanyProcess {
   public String cleanNames(List<String> listOfNames) {
      StringBuilder result = new StringBuilder();
      for(int i=0; i<listOfNames.size(); i++) {
         if(listOfNames.get(i).length()> 1) {
              result.append(capitalizeString(listOfNames.get(i))).append(",");
         }
      }
      return result.substring(0, result.lenth()-1).toString();
   }
  
   public String capitalizeString(String s) {
     return s.substring(0, 1).toUpperCase() + s.substring(1, s.length());
   }
}

1.한글자 이름 필터, 2.대문자로 변형, 3.하나의 문자열로 변환
명령형 언어에서는 세가지 작업에 모두 저수준의 메커니즘을(목록 내에서 반복해서) 사용해야한다.
함수형 언어들은 이런 작업을 위한 helper들을 제공한다.

2.1.2 함수형 처리

함수형 프로그래밍은 프로그램을 수학 공식을 모델링하는 표현과 변형으로 기술. 개발자는 고계함수에 매개변수로 주어지는 함수를 이용하여 저수준의 작업을 커스터마이즈할수 있다.

val employees = List("neal", "s","stu","j","rich","bob","aiden","j","ethan","liam","mason","noah")
val result = employees
.filter(_.length() > 1)
.map(_.capitalize)
.reduce(_ + "," + _)

reduce()는 각요소를 주어진 코드 블록의 규칙에 따라 결합하는 역할을 하는 함수이다.

함수형 사고로의 전환은, 어떤 경우에 세부적인 구현에 뛰어들지 않고 이런 고수준 추상 개념을 적용할지를 배우는 것이다.

고수준 추상적 사고로 얻는이점

  1. 문제의 공통점을 고려하여 다른 방식으로 분류하기를 권장한다는것.
  2. 런타임이 최적화를 잘할 수 있도록 해준다는것
  3. 개발자가 엔진 세부사항에 깊이 파묻힐 경우 불가능한 해답을 가능하게 한다.
    자바의경우 저수준의 반복과정을 제어해야 하기 때문에 스레드 관련 코드가 문제 해결 코드에 들어간다. 스칼라에서는 스트림에 par만 붙이면 된다.

2.3 공통된 빌딩블록

유용한 작업들은 함수형 언어 및 프레임워크 어디에나 존재

2.3.1 필터 -> 주어진 조건에 맞는 컬렉션의 부분집합을 구할때 사용

사용자가 정한 조건으로 목록에 있는 요소들을 필터하여 더 작은 목록을 만드는것

(예) 자바8에서의 필터작업

public static IntStream factorsOf(int number) {
  return range(1, number + 1)
.filter(potential -> number % potential  ==0);
}

1부터 대상 숫자까지의 목록을 만들고, filter()메서드를 적용하여 약수만 구한다.

2.3.2 맵

-> 컬렉션의 각 요소에 같은 함수를 적용하여 새로운 컬렉션을 만든다.

2.3.3 폴드/리듀스

-> 목록 조작 개념의 특별한 변형. 컬렉션의 요소를 하나씩 다른 함수로 처리할때 사용.

2.4 골치 아프게 비슷비슷한 이름들

함수형 언어들은 이름은 다르지만 같은 역할을 하는 함수들이 있다.
-> 유사성을 터득하면 좋다

2.4.1 필터

스칼라
filter() //입력 조건에 따라 목록을 필터링
partition() //컬렉션을 여러 조각으로 분리한 결과를 리턴
find() //조건을 만족시키는 첫 번째 요소만 반환, option으로 래핑 Some, None
takeWhile //조건을 만족시키는 값들의 최대 집합을 리턴

List(1,2,3,-4,5,6,7,8,9,10) takeWhile(_>0)  
//List(1,2,3)  

dropWhile //조건을 만족시키는 최다수의 요소를 건너뛴다.

val words = List("the", "quick","brown","fox","jumped","over","the","lazy","dog")  
words dropWhile (_startWith "t")  
//List("quick","brown","fox","jumped","over","the","lazy","dog")  

그루비
findAll() //함수형 언어에서의 전통적인 filter()
spilt() //partition()과 유사
find() //find의 결과가 없을때는 null리턴
takeWhile
dropWhile

2.4.2 맵

2.4.3 폴드/리듀스

리듀스에 주어지는 함수 또는 연산자는 주로 두개의 매개변수를 받아서 하나의 결과를 리턴하여 목록을 처리한다.

스칼라
//폴드
foldLeft:왼쪽 폴드는 초기값을 시작으로 모든 요소들을 하나씩 왼쪽으로 결합해서 최종 결과를 구한다.

List.range(1,10).foldLeft(0)(_+_)  
//45  

//리듀스
reduceLeft: 첫째요소가 연산의 좌항이라고 간주한다.

List.range(1, 10) reduceLeft((a, b) => a+b)     
List.range(1, 10) reduceLeft(_+_)   
// 1 + 2 =  3
// 3 + 3 =  6
// 6 + 4 = 10
//10 + 5 = 15
//15 + 6 = 21
//21 + 7 = 28
//28 + 8 = 36
//36 + 9 = 45
//45  

reduceRight: 연산자가 적용되는 순서를 바꿀때 사용(연산의 방향을 바꾼다)
-> 연산의 결과를 두번째 매개변수로 사용함을 알수 있다.

List.range(1, 10) reduceRight(_+_)  
//8 -   9  = -1  
//7 - (-1) =  8  
//6 -   8  = -2  
//5 - (-2) =  7  
//4 -   7  = -3  
//3 - (-3) =  6  
//2 -   6  = -4  
//1 - (-4) =  5  

리듀스와 폴드의 차이

reduceLeft[B>:A](op:(B,A) => B):B 시그니처  
   : 각 요소를 결합시키는 함수가 유일한 매개변수이다. 초기 값은 컬렉션의 첫 번째 요소로 간주한다.  
foldLeft[z:B](op:(B,A) => B):B 시그니처  
   : 초기 시드 값을 포함 하기 때문에 목록의 요소와 다른 자료형의 리턴 값을 가능하게 해준다.  

그루비

(1..10).inject {a, b -> a + b}     
//55  

초기값을 받는 형태

(1..10).inject(0,  {a, b -> a + b})  
//55  

클로저

(reduce + (range 1 11))  
;55    

클로저의 (reduce)함수는 선택적으로 초기 값을 받아서 스칼라의 reduce(), foldLeft() 두 경우를 해결한다.

-> 유사성을 터득하면 문법적으로 놀랍게도 함수형 언어들이 중복되는 기능을 지원한다는것을 깨달을 것이다.

Clone this wiki locally