: 함수를 마치 클래스에서 만들어 낸 인스턴스처럼 취급하는 방법
: 함수를 파라미터로 넘겨줄 수도 있고, 결과값으로 반환 받을 수도 있는 방법
참고로 코틀린에서는 모든 함수를 고차함수로 사용 가능하다.

그렇다면 함수는 파라미터로 전달할 때 그에대한 자료형을 어떻게 표현할까?

파라미터로 넣고자 하는 함수에 들어가는 자료형을 나열하고, 반환받을 자료형을 넣어주면 된다.

이미지를 보면 a라는 함수는 String값을 파라미터로 받아 출력을 하게끔 하고, 그에 대해 파라미터로 넣는 고차함수 b는 출력문을 작성한다.

파라미터로 넣을 때 자료형으로 function (String) -> Unit으로 넣어주면 b 함수는 a의 파라미터로 들어가게된다.
main에서는 호출할 때 b(::a)로 표기를 하는데, 이는 b 함수는 받아온 a 함수에 "b가 호출한" 이라는 값을 넘겨서 호출한다. 고차함수로 파라미터로 넘긴 함수를 호출할 때는 반드시 "::" 키워드를 명시해줘야 한다.
: 함수를 람다식으로 표현하는 방식
: 일반함수와는 달리 그 자체가 고차함수이기 때문에 별도의 연산자 없이도 변수에 담을 수 있다.

b에서 파라미터를 받기위해 자료형 선언한 것 같이 c에도 자료형을 같은 형식으로 작성 후 람다 형식인 -> 로 넘긴다. 그 후 {} 내 받은 인자 이름과 동작 구문을 적용시키면 된다.

또한 람다함수 사용 시 코틀린의 타입추론을 이용하여 코드를 조금 더 축약할 수 있다.
val calculate: (Int, Int) -> Int = { a, b ->
println(a)
println(b)
a+b
}
이 구조처럼 람다함수에서는 여러 구문으로 작성 가능하고, 마지막 구문인 a+b값을 Int로 반환한다.
val a: () => Unit = { println("파라미터가 없음") }
이 구조처럼 파라미터가 없어도 실행할 구문들 작성 시 정상 작동한다.
val c: (String) -> Unit = { println("$it 람다함수") }
이것처럼 파라미터가 하나라면 this와 비슷하게 it으로 가리켜서 파라미터 적용 가능하다.
: 함수형 언어의 특징을 좀 더 편리하게 사용할 수 있도록 기본 제공하는 함수들
예를 들어, 클래스의 인스턴스를 Scope함수에 전달하면 인스턴스의 속성이나 함수를 좀 더 깔끔하게 불러 사용 가능하다.
: 인스턴스 생성 이후 변수에 담기 전에 초기화 과정을 수행 시 사용

원래 책 이름과 가격을 속성으로 정의 내린 클래스를 이용하여 인스턴스 객체를 생성 후 책 이름 수정 및 가격 할인을 할 때 이미지와 같이 했다면

apply를 활용하여 람다함수를 만들고, apply scope 안에 직접 인스턴스 속성과 함수를 참조연산자 없이 사용 가능하다.
또한 apply는 인스턴스 자신을 다시 반환하므로 생성되자마자 조작된 인스턴스를 변수에 바로 넣어줄 수 있다.
이는 main함수와 별도의 scope에서 인스턴스의 변수와 함수를 조작하므로 코드가 깔끔해진다는 장점이 있다.
: 스코프 안에 참조연산자를 사용하지 않아도 된다는 점은 같지만 일반 람다함수처럼 인스턴스 대신 마지막 구문에 결과값을 반환한다는 차이점이 있다.
: 이미 인스턴스가 만들어진 후에 인스턴스의 함수나 속성을 scope 내에서 사용해야할 때 유용

아까 출력문에서와 같이 인스턴스 객체에 접근할 시 참조연산자로 접근을 해야하지만

이렇게 run이라는 스코프 함수를 통해 참조연산자를 이용하여 접근 안해도 출력이 잘된다.
: run과 동일한 기능을 가지지만 단지 인스턴스를 참조연산자 대신 파라미터로 받는다는 차이가 있다.
a.run {...}
with(a) {...}
이렇듯 그냥 스코프 함수 호출 시 참조 연산자 대신 파라미터로 받는 방식에만 차이가 있다.
: apply/run 처럼 참조연산자 없이 인스턴스의 변수와 함수를 사용할 수 있었다면
also/let은 마치 파라미터로 인스턴스를 넘긴 것처럼 it을 통해 인스턴스 사용 가능하다.
also/let 사용 이유?
=> 같은 이름의 변수나 함수가 scope 외부에 중복되어 있는 경우에 혼란을 방지하기 위해서이다.

이렇게 main 함수 내 같은 이름으로 price를 5000으로 초기화 및 선언을 한다면 결과는 할인받은 가격의 8000이 떠야 하지만 5000으로 출력됨을 알 수 있다.
이는 run 함수가 인스턴스 내의 price 속성보다 run이 속해있는 main함수의 price 변수를 우선시하고 있기 때문이다.

이럴 때 run을 let으로 변경 후 a의 속성을 가리키도록 it으로 참조연산자를 통해 접근한다면 정상적으로 작동한다.
같은 방식으로 apply에서도 그런 상황이 발생한다면 같은 짝꿍인 also로 처리하면 된다.