Unison에서 능력을 요구하는 함수가 어떻게 타입체킹되는지, 함수 타입 시그니처와 handle 블록에 의해 능력이 어떤 규칙으로 허용되는지를 설명합니다.
능력(ability)에 대해 사용되는 일반적인 타입체킹 규칙은 다음과 같습니다.
능력 {A1, A2} 를 요구하는 함수를 호출하려면, 최소한 {A1, A2} 능력이 사용 가능한(context에 존재하는) 곳에서만 호출해야 합니다. 그렇지 않으면 타입체커가 능력 검사 실패(ability check failure)로 에러를 보고합니다.
능력은 handle 블록(아래에서 설명)이나 타입 시그니처를 통해 사용 가능하도록 만들 수 있습니다. 예를 들어, 함수 본문이 Text ->{IO} Nat 인 함수 안에서는 {IO} 능력이 사용 가능하므로, 다음이 허용됩니다.
f : Nat ->{} Nat 함수를 호출할 수 있습니다. f 의 능력 요구 사항은 {} 이고, 이는 사용 가능한 능력 {IO} 의 부분집합이기 때문입니다.g : Text ->{IO} () 함수 또한 호출할 수 있습니다. g 의 요구 능력은 {IO} 이고, 이는 사용 가능한 {IO} 능력의 부분집합이기 때문입니다.여러 인자를 받는 함수의 경우, 다른 규칙이 필요해 보일 수 있지만, 규칙은 동일합니다. 함수 본문은 시그니처에 있는 해당 함수 타입에 붙은 능력만 사용할 수 있습니다.
아래 예시는 시그니처에 따르면 함수 본문이 순수해야(pure) 하기 때문에 타입체킹에 실패합니다.
unisondoesNotWork : Text ->{Exception,IO} Text ->{} Nat doesNotWork arg1 arg2 = printLine "Does not work!" 42
하지만, 순수한 함수를 반환하기 전에 IO 를 수행하면, 타입체킹이 잘 통과합니다.
unisondoesWork : Text ->{IO, Exception} Text -> Nat doesWork arg1 = printLine "Works great!" arg2 -> 42
함수 본문 안에 포함되어 있지 않은 최상위(top-level) 정의 는 순수해야 한다는 제약이 있습니다. 예를 들어, 아래 코드는 타입체킹에 실패합니다.
unisonmsg = printLine "hello"
하지만 다음과 같이 작성하면 타입체킹이 잘 됩니다.
unisonmsg = '(printLine "Hello")
이 경우 printLine 이 이제 함수 본문 안에 들어가게 되고, 그 함수의 요구 능력은 {IO} 로 추론(infer)됩니다. (직접 시도해 보세요!)
🤓 최상위 정의가 순수해야 한다는 이 제약은, 향후 Unison 버전에서 제거될 수도 있습니다.