시스템 클래스 FUNCTION — 함수

시스템 클래스 FUNCTION — 함수

Common Lisp에서 함수는 일급 객체이자, 실행될 코드를 감싼 객체입니다. 이 페이지는 FUNCTION이라는 타입이 무엇인지, 그리고 함수 타입 지정자로 어떻게 함수의 시그니처를 기술하는지 정리한 내용이에요. 함수 본문 자체보다 타입에 초점을 맞춰 볼게요.

출처: CLHS — System Class FUNCTION

클래스 우선순위 목록

function, t

본문 (Description)

함수(function)적절한 개수의 인자가 주어졌을 때 실행될 코드를 나타내는 객체입니다. 함수는 다음과 같은 경로로 만들어집니다.

  • function 특수 형식(special form)
  • coerce 함수
  • compile 함수

그리고 함수는 funcall, apply, multiple-value-call첫 번째 인자로 사용해 직접 호출할 수 있어요.

복합 타입 지정자 (Compound Type Specifier)

  • Kind: Specializing
  • 구문:
function [arg-typespec [value-typespec]]
arg-typespec ::= (typespec*
                  [&optional typespec*]
                  [&rest typespec]
                  [&key (keyword typespec)*])
  • 인자:

    • typespec — 타입 지정자
    • value-typespec — 타입 지정자

function 타입 지정자의 리스트 형태는 선언(declaration)에는 쓸 수 있지만, 판별(discrimination)에는 쓸 수 없습니다. 즉 실제로 객체가 그 타입인지 검사하는 용도로는 쓰지 못해요.

이 타입의 각 원소는, argj 타입들이 지정하는 타입의 인자를 받고 value-type이 지정하는 타입의 값을 반환하는 함수입니다. 인자 타입 리스트에는 &optional, &rest, &key, &allow-other-keys 마커가 나타날 수 있어요.

몇 가지 세부 규칙을 정리할게요.

  • &rest에 주어지는 타입 지정자는 대응 변수의 타입이 아니라 각 실제 인자(args)의 타입입니다.
  • &key 파라미터는 (keyword type) 형태의 리스트로 제공해야 해요. keyword는 호출의 실제 인자에 반드시 등장하는 올바른 키워드-이름(keyword-name) 기호여야 하며, 보통 KEYWORD 패키지의 기호지만 어떤 기호든 가능합니다.
  • 함수 타입 지정자의 람다 리스트에 &key가 주어지면, 그 키워드 파라미터들은 완전(complete) 한 목록이에요. 다만 &allow-other-keys가 함께 있으면 그렇지 않아요. &allow-other-keys는 다른 키워드 인자가 실제로 제공될 수 있고, 제공되면 사용할 수 있다는 표시입니다.

예를 들어 make-list 함수의 타입은 다음과 같이 선언할 수 있어요.

(function ((integer 0) &key (:initial-element t)) list)

value-type여러 값을 돌려주는 함수의 타입을 나타내기 위해 values 타입 지정자일 수도 있어요.

ftype 선언의 의미

다음 형태의 선언을 생각해 볼게요.

(ftype (function (arg0-type arg1-type ...) val-type) f)

그 선언의 스코프 안에서 어떤 형태 (f arg0 arg1 ...)든 다음과 동치로 취급됩니다.

(the val-type (f (the arg0-type arg0) (the arg1-type arg1) ...))

즉, 인자 중 하나라도 지정된 타입이 아니거나 결과가 지정된 타입이 아니면 결과가 정의되지 않습니다(consequences are undefined). 특히 어떤 인자가 올바른 타입이 아니면, 결과가 지정된 타입이라는 보장이 없어요.

따라서 함수에 대한 ftype 선언은 함수의 실제 정의가 아니라 함수를 호출하는 측(호출 자체) 을 기술하는 것이에요.

변수에 대한 타입 선언도 비슷하게 생각할 수 있어요.

(type (function (arg0-type arg1-type ...) val-type) fn-valued-variable)

이 선언은 "스코프 안에서 fn-valued-variable의 값을 지정된 타입이 아닌 인자로 호출하면 결과가 미지정(unspecified)이고, 유효한 호출의 결과는 val-type 타입이다"라는 뜻입니다.

변수 타입 선언처럼, 중첩된 함수 선언은 타입들의 교집합(intersection) 을 의미합니다. 예를 들어 다음 두 ftype 선언이 동시에 유효하다면,

(ftype (function (arg0-type1 arg1-type1 ...) val-type1) f)
(ftype (function (arg0-type2 arg1-type2 ...) val-type2) f)

그 공유 스코프 안에서 f에 대한 호출은 마치 다음처럼 선언된 것처럼 취급할 수 있어요.

(ftype (function ((and arg0-type1 arg0-type2)
                  (and arg1-type1 arg1-type2 ...) ...)
                  (and val-type1 val-type2))
       f)

유효한 ftype 선언 중 하나 또는 전부를 무시하는 것도 허용됩니다. 변수에 대한 두 개 이상의 타입 선언도, 둘 다 함수 선언이라면 마찬가지로 결합됩니다.

더 알아보기 (Learn more)