Future는 부작용 계산에 대한 처리를 Future에서 할경우 예상치 못한 결과 즉 side-effect를 가질 수 있다.
따라서 Future와 같은 성질의 다른 안전한 참조 투명성을 지닌 다른 유형인 찾아 보면 다음과 같이 Funtion 의 합성을 통하여 연산의 지연으로 Future 와 같은 미래의 연산을 나타 낼 수 있다.
Function
fn01: X => A, fn02: A => B 일때 fn02 compose fn01 이면 X => B 의 함수를 얻을 수 있다. 이를 통해 연산을 chain형태로 나타 낼 수 있으며 이때 이는 연산의 표현이며 표현이 곧 실행을 의미 하지는 않는다.
위의 예제를 보면 어떤 단일 함수를 map으로 sequence하게 연결함으로써 어떤 연산의 chain을 만들어 낼 수 있으며 이는 단지 연산의 선언적 표현으로 실제 실행은 되지 않고 언제가 호출시 실행된다는 점에서 Future와 비슷하다고 할 수 있겠다.
Higher Kinded type
Functor, Monad, Applicative Functor 등을 이야기 할때 F[_] 이런 형태를 이야기 하지 않을 수 없다.
우리가 java에서 List<Integer>, List<String> 등 Integer, String 등의 어떠한 정해지지 않은 유형을 담는 List를 표현할때 List<A> 라고 표현한다. Map은 Map<K,V> 이렇게.
그럼 저런 List<A>, Map<K,V> 처럼 List나 Map 어떠한 유형을 내포하는 유형인데 List인지, Map 인지 정해지지 않은 유형을 표현할때는 어떻게 표현할까?
이게 고계타입(Higher Kinded type)이다.
일전에 Functor 게시글에서 이를 Higher Kinded type(고계타입 이라고)라고 하는데 이는 어떠한 type를 유형을 가지는 유형를 표현한 것이다.
cats Functor
type class
api에 보면 companion object의 apply method 은 아래와 과 같다.
위의 코드에서 apply method가 적용될때는 F라는 고계타입에 해당하는 Functor가 암시적으로 받드시 있어야 한다. 따라서 import cats.instance.list._ 처럼 cats instance를 import해야 한다.
Functor type class & instance
기존에 해왔듯이 Functor의 type class 도 같다. Functor type class와 companion object의 apply method가 있고 실제 기본 유형에 대한 instance들은 cats.instances에 있다.
Functor syntax
위의 Function 의 예제 코드에서 function01 map function02 map function03 처럼 사용했다. 하지만 Function에는 map method가 없다.
따라서 이것도 Function syntax가 관련될을 것이라 짐작 할 수 있다.
List 나 Option등은 기존에 map method 가 있다. 이런경우 List나 Option등의 map method가 적용된다.
구지 cats.Function 의 map을 사용해하고 싶은 경우 좀 꽁수를 써야 한다.
src가 map method를 사용하려면 cats.syntax.functor._ 가 있어야 된다.
cats.syntax.functor._ 에는 아마도 위에처럼 FunctorOps 암시자가 있겠지
Functor law
Functor law는 다음과 같다.
Identity: 즉 Functor에 항등함수를 적용하면 원래의 Functor와 같다.
Composition: 두 함수 f와 g로 합성후 map를 적용한 것은 함수 f를 map적용한 후 다음 함수 g를 map 적용한 것과 동일하다.
위의 Functor type class, instance, syntax등을 이용하여 functor law예제를 보자
Custom Functor 만들기
Functor의 apply method는 암시자로 고계타입의 type parameter를 받는 Functor instance를 받는다.
따라서 custom Functor를 만들경우 implicit F에 해당하는 Functor instance를 암시자로 제공하면 된다.
Future에 대한 Functor를 만들경우 좀 고려해야 할 것이 ExecutionContext가 암시자로 필요하다는 것이다. Future에서 암시자를 받기 때문이다.
따라서 아래 코드와 같이 Context안에 ExecutionContext 암시자가 있어야 한다.