누군가 나에게 종속 타이핑을 설명 할 수 있습니까? Haskell, Cayenne, Epigram 또는 기타 기능적 언어에 대한 경험이 거의 없으므로 사용할 수있는 용어가 간단할수록 더 감사 할 것입니다!
답변
이것을 고려하십시오 : 모든 괜찮은 프로그래밍 언어에서 함수를 작성할 수 있습니다.
def f(arg) = result
여기에서 f
값을 취하고 값 arg
을 계산합니다 result
. 값에서 값으로의 함수입니다.
이제 일부 언어에서는 다형성 (일명 일반) 값을 정의 할 수 있습니다.
def empty<T> = new List<T>()
여기에서 empty
유형을 취하고 T
값을 계산합니다. 유형에서 값으로의 함수입니다.
일반적으로 일반 유형 정의를 가질 수도 있습니다.
type Matrix<T> = List<List<T>>
이 정의는 유형을 취하고 유형을 리턴합니다. 유형에서 유형으로의 함수로 볼 수 있습니다.
평범한 언어가 제공하는 것이 너무 많습니다. 네 번째 가능성, 즉 값에서 유형으로 함수를 정의하는 경우 언어를 종속 유형이라고합니다. 즉, 값에 대한 유형 정의 매개 변수화 :
type BoundedInt(n) = {i:Int | i<=n}
일부 주류 언어에는 혼동해서는 안되는 가짜 형태가 있습니다. 예를 들어 C ++에서 템플릿은 값을 매개 변수로 사용할 수 있지만 적용 할 때 컴파일 타임 상수 여야합니다. 진정한 의존형 언어에서는 그렇지 않습니다. 예를 들어 위의 유형을 다음과 같이 사용할 수 있습니다.
def min(i : Int, j : Int) : BoundedInt(j) =
if i < j then i else j
여기서 함수의 결과 유형 은 실제 인수 값 j
, 즉 용어 에 따라 다릅니다 .
답변
종속 유형을 사용 하면 컴파일 시간에 더 많은 논리 오류 를 제거 할 수 있습니다 . 이를 설명하기 위해 기능에 대한 다음 사양을 고려하십시오 .f
함수
f
는 짝수 정수만 입력 해야합니다 .
종속 유형이 없으면 다음과 같이 할 수 있습니다.
def f(n: Integer) := {
if n mod 2 != 0 then
throw RuntimeException
else
// do something with n
}
여기서 컴파일러 n
는 실제로 짝수 인지 감지 할 수 없습니다 . 즉, 컴파일러의 관점에서 다음 표현식이 괜찮은지 감지 할 수 없습니다 .
f(1) // compiles OK despite being a logic error!
이 프로그램은 실행되고 런타임에 예외를 발생시킵니다. 즉, 프로그램에 논리 오류가 있습니다.
이제 종속 유형을 사용하면 훨씬 더 많은 표현을 사용할 수 있으며 다음과 같이 작성할 수 있습니다.
def f(n: {n: Integer | n mod 2 == 0}) := {
// do something with n
}
다음 n
은 종속 유형 {n: Integer | n mod 2 == 0}
입니다. 이것을 크게 읽는 것이 도움이 될 수 있습니다.
n
각 정수를 2로 나눌 수있는 정수 세트의 구성원입니다.
이 경우 컴파일러는 컴파일 타임에 홀수를 전달한 논리 오류를 감지 f
하여 프로그램이 처음에 실행되지 않도록합니다.
f(1) // compiler error
다음은 이러한 요구 사항을 충족 하는 함수를 구현하는 방법에 대한 Scala 경로 종속 유형 을 사용한 예시입니다 f
.
case class Integer(v: Int) {
object IsEven { require(v % 2 == 0) }
object IsOdd { require(v % 2 != 0) }
}
def f(n: Integer)(implicit proof: n.IsEven.type) = {
// do something with n safe in the knowledge it is even
}
val `42` = Integer(42)
implicit val proof42IsEven = `42`.IsEven
val `1` = Integer(1)
implicit val proof1IsOdd = `1`.IsOdd
f(`42`) // OK
f(`1`) // compile-time error
핵심은 값 n
이 다음과 같이 값 유형에 어떻게 나타나는지 확인 하는 proof
것입니다 n.IsEven.type
.
def f(n: Integer)(implicit proof: n.IsEven.type)
^ ^
| |
value value
유형 n.IsEven.type
은 값 에 따라 다르 n
므로 용어 종속 유형 이라고 말합니다 .
답변
C ++를 알게된다면 동기를 부여하는 예제를 쉽게 제공 할 수 있습니다.
컨테이너 유형과 인스턴스 두 개가 있다고 가정 해 보겠습니다.
typedef std::map<int,int> IIMap;
IIMap foo;
IIMap bar;
다음 코드 조각을 고려하십시오 (foo가 비어 있지 않다고 가정 할 수 있음).
IIMap::iterator i = foo.begin();
bar.erase(i);
이것은 명백한 쓰레기입니다 (그리고 아마도 데이터 구조를 손상시킬 것입니다). 그러나 “iterator into foo”와 “iterator into bar”는 IIMap::iterator
의미 상 완전히 호환되지 않더라도 동일한 유형이기 때문에 유형 검사는 괜찮습니다 .
문제는 반복기 유형이 컨테이너 유형 에만 의존하는 것이 아니라 실제로 컨테이너 객체 에 의존해야 한다는 것입니다. 즉, “비 정적 멤버 유형”이어야합니다.
foo.iterator i = foo.begin();
bar.erase(i); // ERROR: bar.iterator argument expected
이러한 기능, 즉 용어 (foo)에 의존하는 유형 (foo.iterator)을 표현하는 능력은 정확히 종속 입력이 의미하는 바입니다.
이 기능을 자주 보지 못하는 이유는 많은 수의 웜이 열리기 때문입니다. 컴파일 타임에 두 가지 유형이 동일한 지 확인하기 위해 갑자기 두 가지 표현을 증명해야하는 상황에 처하게됩니다. 동일합니다 (런타임에 항상 동일한 값을 생성 함). 당신은 위키 피 디아의 비교한다면 결과, 의존적으로 입력 된 언어의 목록을 그와 함께 정리 피 인증 목록 당신은 의심스러운 유사성을 알 수 있습니다. 😉
답변
책 유형 및 프로그래밍 언어 (30.5) 인용 :
이 책의 대부분은 다양한 종류의 추상화 메커니즘을 공식화하는 것과 관련이 있습니다. 간단하게 입력 된 람다-미적분에서 우리는 용어를 취하고 하위 용어를 추상화하는 작업을 공식화하여 나중에 다른 용어에 적용하여 인스턴스화 할 수있는 함수를 생성했습니다. System에서는
F
용어를 취하고 형식을 추상화하여 다양한 형식에 적용하여 인스턴스화 할 수있는 용어를 생성하는 작업을 고려했습니다. 에λω
, 우리는 단순히 형식화 된 람다-미적분 “한 단계 위로”의 메커니즘을 요약하여 형식을 취하고 하위 식을 추상화하여 나중에 다른 형식에 적용하여 인스턴스화 할 수있는 형식 연산자를 얻습니다. 이러한 모든 형태의 추상화를 편리하게 생각할 수있는 방법은 다른 표현에 의해 색인 된 표현 군에 관한 것입니다. 일반적인 람다 추상화λx:T1.t2
는 용어로[x -> s]t1
인덱싱 된 용어 군s
입니다. 마찬가지로 유형 추상화λX::K1.t2
는 유형별로
인덱싱 된 용어 모음이고 유형 연산자는 유형별로 인덱싱 된 유형 모음입니다.
λx:T1.t2
용어로 색인 된 용어 군
λX::K1.t2
유형별로 색인 된 용어 군
λX::K1.T2
유형별로 인덱싱 된 유형 계열이 목록을 살펴보면 아직 고려하지 않은 한 가지 가능성이 있음이 분명합니다. 용어로 색인 된 유형의 패밀리입니다. 이러한 형태의 추상화는 종속 유형의 루 브릭에 따라 광범위하게 연구되었습니다.
답변
![](http://daplus.net/wp-content/uploads/2023/04/coupang_part-e1630022808943-2.png)