Programming Languages

이상한 Kotlin의 세계 - Iterable.map()

Sushi Yun 2020. 1. 17. 16:23

Java야 뭐, 기존 타입이 functional programming에 적합하지 않기 때문에, Array, List, Set 등등의 타입을 다 Java 8부터 제공하는 Stream으로 변환해놓고 처리하니까...

import java.util.*;
import java.util.stream.*;


public class A {
	public static void main(String[] args) {
	    // 1. Array
		String[] ss = { "1", "2", "3" };
		Stream.of(ss)
			.map(s -> Integer.valueOf(s))
			.forEach(i -> System.out.println("Value: " + i + " (" + i.getClass().getName() + ")"));
            
		// 2. List
        List<String> sl = Arrays.asList("1", "2", "3");
		sl.stream()
			.map(s -> Integer.valueOf(s))
			.forEach(i -> System.out.println("Value: " + i + " (" + i.getClass().getName() + ")"));
            
		// 3. Set
		Set<String> ss = Set.of("1", "2", "3"); // java 9
        ss.stream()
            .map(s -> Integer.valueOf(s))
            .forEach(i -> System.out.println("Value: " + i + " (" + i.getClass().getName() + ")"));
            
        // X. 그 외 Map 등은 생략
	}
}

 

Scala는 알아보기도 힘든-.- 시그니처를 가진 map()을 호출하고나면 원래의 타입을 리턴한다. 정확히는 모르겠지만, List, Set, Array 등의 내부에 정의되어있는 map()에서 implicit으로 사용하는 CanBuildFrom 덕분에 원래 타입이 유지되는 것으로 보인다. (자세히 아시는 분 있으면 코멘트 부탁드립니다!)

final override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That = ???

class GenericCanBuildFrom[A](implicit tag: ClassTag[A]) extends CanBuildFrom[CC[_], A, CC[A]]

 

근데 왜 Kotlin은 어떤 타입에서 시작하든 map의 결과가 List가 되는걸까. 아예 Iterable.map()의 시그니처에 리턴 타입이 List라고 정의되어있다. (link to Kotlin Reference - map)

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R>

Kotlin에서는 map()이 단순 functor가 아닌가보다...라고 생각하면 되긴 하는데 완전 별로다 -_- List가 아닌 다른 Collection의 요소에 어떤 함수를 적용한 후 그 타입을 그대로 가지고 싶으면 어떻게 해야 하지?_?

 

----

추가: Kotlin의 Sequence라는 타입이 Java로 치면 Stream 같은 역할을 수행한다고 한다. (sequential data의 lazy evaluation)

이 타입에서는 (중간(intermediate) 연산들을 수행한 후) 종료(terminal) 연산할 때 최종 타입이 정해진다. 그러므로 monad인 것 처럼 사용할 수 있다.

public fun <T> Sequence<T>.toList(): List<T> {
    return this.toMutableList().optimizeReadOnlyList()
}
public fun <T> Sequence<T>.toSet(): Set<T> {
    return toCollection(LinkedHashSet<T>()).optimizeReadOnlySet()
}
public inline fun <T, K, V> Sequence<T>.associate(transform: (T) -> Pair<K, V>): Map<K, V> {
    return associateTo(LinkedHashMap<K, V>(), transform)
}
public inline fun <T, K> Sequence<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>> {
    return groupByTo(LinkedHashMap<K, MutableList<T>>(), keySelector)
}

'Programming Languages' 카테고리의 다른 글

이상한 Kotlin의 세계 - Type inference  (0) 2020.05.17
Scala Option  (0) 2017.01.29
[추상자료형] 리스트(List)  (0) 2016.09.18