Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

Intersection type

From Wikipedia, the free encyclopedia
Data type for values having two types
Type systems
General concepts
Major categories
Minor categories

Intype theory, anintersection type can be allocated to values that can be assigned both the typeσ{\displaystyle \sigma } and the typeτ{\displaystyle \tau }. This value can be given the intersection typeστ{\displaystyle \sigma \cap \tau } in anintersection type system.[1]Generally, if the ranges of values of two types overlap, then a value belonging to theintersection of the two ranges can be assigned theintersection type of these two types. Such a value can be safely passed as argument to functions expectingeither of the two types.For example, inJava the classBoolean implements both theSerializable and theComparable interfaces. Therefore, an object of typeBoolean can be safely passed to functions expecting an argument of typeSerializable and to functions expecting an argument of typeComparable.

Intersection types arecomposite data types. Similar toproduct types, they are used to assign several types to an object.However, product types are assigned totuples, so that each tuple element is assigned a particular product type component. In comparison, underlying objects of intersection types are not necessarily composite. A restricted form of intersection types arerefinement types.

Intersection types are useful for describingoverloaded functions.[2] For example, ifnumber=>number is the type of function taking a number as an argument and returning a number, andstring=>string is the type of function taking a string as an argument and returning a string, then the intersection of these two types can be used to describe (overloaded) functions that do one or the other, based on what type of input they are given.

Contemporary programming languages, includingCeylon, Flow,Java,Scala,TypeScript, andWhiley (seecomparison of languages with intersection types), use intersection types to combine interface specifications and to expressad hoc polymorphism.Complementingparametric polymorphism, intersection types may be used to avoid class hierarchy pollution fromcross-cutting concerns and reduceboilerplate code, as shown in theTypeScript example below.

Thetype theoretic study of intersection types is referred to as theintersection type discipline.[3]Remarkably, program termination can be precisely characterized using intersection types.[4] Consequently,type inference for infinite-intersection types isundecidable, but it is decidable for all finite rank intersection types.[5]

TypeScript example

[edit]

TypeScript supports intersection types,[6] improving expressiveness of the type system and reducing potential class hierarchy size, demonstrated as follows.

The following program code defines the classesChicken,Cow, andRandomNumberGenerator that each have a methodproduce returning an object of either typeEgg,Milk, ornumber.Additionally, the functionseatEgg anddrinkMilk require arguments of typeEgg andMilk, respectively.

classEgg{privatekind:"Egg"}classMilk{privatekind:"Milk"}// produces eggsclassChicken{produce(){returnnewEgg();}}// produces milkclassCow{produce(){returnnewMilk();}}// produces a random numberclassRandomNumberGenerator{produce(){returnMath.random();}}// requires an eggfunctioneatEgg(egg:Egg){return"I ate an egg.";}// requires milkfunctiondrinkMilk(milk:Milk){return"I drank some milk.";}

The following program code defines thead hoc polymorphic functionanimalToFood that invokes the member functionproduce of the given objectanimal.The functionanimalToFood hastwo type annotations, namely((_:Chicken)=>Egg) and((_:Cow)=>Milk), connected via the intersection type constructor&.Specifically,animalToFood when applied to an argument of typeChicken returns an object of typeEgg, and when applied to an argument of typeCow returns an object of typeMilk.Ideally,animalToFood should not be applicable to any object having (possibly by chance) aproduce method.

// given a chicken, produces an egg; given a cow, produces milkletanimalToFood:((_:Chicken)=>Egg)&((_:Cow)=>Milk)=function(animal:any){returnanimal.produce();};

Finally, the following program code demonstratestype safe use of the above definitions.

varchicken=newChicken();varcow=newCow();varrandomNumberGenerator=newRandomNumberGenerator();console.log(chicken.produce());// Egg { }console.log(cow.produce());// Milk { }console.log(randomNumberGenerator.produce());//0.2626353555444987console.log(animalToFood(chicken));// Egg { }console.log(animalToFood(cow));// Milk { }//console.log(animalToFood(randomNumberGenerator)); // ERROR: Argument of type 'RandomNumberGenerator' is not assignable to parameter of type 'Cow'console.log(eatEgg(animalToFood(chicken)));// I ate an egg.//console.log(eatEgg(animalToFood(cow))); // ERROR: Argument of type 'Milk' is not assignable to parameter of type 'Egg'console.log(drinkMilk(animalToFood(cow)));// I drank some milk.//console.log(drinkMilk(animalToFood(chicken))); // ERROR: Argument of type 'Egg' is not assignable to parameter of type 'Milk'

The above program code has the following properties:

  • Lines 1–3 create objectschicken,cow, andrandomNumberGenerator of their respective type.
  • Lines 5–7 print for the previously created objects the respective results (provided as comments) when invokingproduce.
  • Line 9 (resp. 10) demonstrates type safe use of the methodanimalToFood applied tochicken (resp.cow).
  • Line 11, if uncommented, would result in a type error at compile time. Although theimplementation ofanimalToFood could invoke theproduce method ofrandomNumberGenerator, thetype annotation ofanimalToFood disallows it. This is in accordance with the intended meaning ofanimalToFood.
  • Line 13 (resp. 15) demonstrates that applyinganimalToFood tochicken (resp.cow) results in an object of typeEgg (resp.Milk).
  • Line 14 (resp. 16) demonstrates that applyinganimalToFood tocow (resp.chicken) does not result in an object of typeEgg (resp.Milk). Therefore, if uncommented, line 14 (resp. 16) would result in a type error at compile time.

Comparison to inheritance

[edit]

The above minimalist example can be realized usinginheritance, for instance by deriving the classesChicken andCow from a base classAnimal.However, in a larger setting, this could be disadvantageous.Introducing new classes into a class hierarchy is not necessarily justified forcross-cutting concerns, or maybe outright impossible, for example when using an external library. Imaginably, the above example could be extended with the following classes:

  • a classHorse that does not have aproduce method;
  • a classSheep that has aproduce method returningWool;
  • a classPig that has aproduce method, which can be used only once, returningMeat.

This may require additional classes (or interfaces) specifying whether a produce method is available, whether the produce method returns food, and whether the produce method can be used repeatedly.Overall, this may pollute the class hierarchy.

Comparison to duck typing

[edit]

The above minimalist example already shows thatduck typing is less suited to realize the given scenario.While the classRandomNumberGenerator contains aproduce method, the objectrandomNumberGenerator should not be a valid argument foranimalToFood.The above example can be realized using duck typing, for instance by introducing a new fieldargumentForAnimalToFood to the classesChicken andCow signifying that objects of corresponding type are valid arguments foranimalToFood.However, this would not only increase the size of the respective classes (especially with the introduction of more methods similar toanimalToFood), but is also a non-local approach with respect toanimalToFood.

Comparison to function overloading

[edit]

The above example can be realized usingfunction overloading, for instance by implementing two methodsanimalToFood(animal:Chicken):Egg andanimalToFood(animal:Cow):Milk.In TypeScript, such a solution is almost identical to the provided example. Other programming languages, such asJava, require distinct implementations of the overloaded method.This may lead to eithercode duplication orboilerplate code.

Comparison to the visitor pattern

[edit]

The above example can be realized using thevisitor pattern.It would require each animal class to implement anaccept method accepting an object implementing the interfaceAnimalVisitor (adding non-localboilerplate code).The functionanimalToFood would be realized as thevisit method of an implementation ofAnimalVisitor.Unfortunately, the connection between the input type (Chicken orCow) and the result type (Egg orMilk) would be difficult to represent.

Comparison with parametric polymorphism

[edit]

Parametric polymorphism is conceptually equivalent to infinite intersection types.[7]

Intersection types have been promoted as being "compositional" in contrast with thelet-bound polymorphism of ML (a restricted form of parametric polymorphism) because intersection types haveprincipal typings while ML's type system does not (not to be confused with principal types, which ML does enjoy). The lack of principal typings in ML translates into the need to evaluate some expressions before others in an ML program; essentially resulting in a data dependency at type-inference level in ML, in particular inlet expressions.[8] Consequently, intersection types have been proposed as a way to improveincremental compilation[9] and/orgradual typing.[10]

On the other hand, intersection types have been criticized for not being compositional in another sense, namely that in a putative system that uses only intersection types but has no parametric polymorphism, inferred may types depend on the local features of a module, which may compose badly with other modules unless whole program compilation happens at source level. As a trivial example, anidentity function that is exposed through a public interface, e.g. exported by a module, ideally is parametrically polymorphic, so that it can be used with future types that the writer (of that function) doesn't yet know about. However, in a system that only has intersection types, such a function would be inferred to intersect at best over types existing when it is compiled.[11]

Limitations

[edit]

On the one hand, intersection typescan be used to locally annotate different types to a function without introducing new classes (or interfaces) to the class hierarchy.On the other hand, this approachrequires all possible argument types and result types to be specified explicitly.If the behavior of a function can be specified precisely by either a unified interface, parametric polymorphism, orduck typing, then the verbose nature of intersection types is unfavorable.Therefore, intersection types should be considered complementary to existing specification methods.

Dependent intersection type

[edit]

Adependent intersection type, denoted(x:σ)τ{\displaystyle (x:\sigma )\cap \tau }, is adependent type in which the typeτ{\displaystyle \tau } may depend on the term variablex{\displaystyle x}.[12]In particular, if a termM{\displaystyle M} has the dependent intersection type(x:σ)τ{\displaystyle (x:\sigma )\cap \tau }, then the termM{\displaystyle M} hasboth the typeσ{\displaystyle \sigma } and the typeτ[x:=M]{\displaystyle \tau [x:=M]}, whereτ[x:=M]{\displaystyle \tau [x:=M]} is the type which results from replacing all occurrences of the term variablex{\displaystyle x} inτ{\displaystyle \tau } by the termM{\displaystyle M}.

Scala example

[edit]

Scala supports type declarations[13] as object members. This allows a type of an object member to depend on the value of another member, which is called apath-dependent type.[14]For example, the following program text defines a Scala traitWitness, which can be used to implement thesingleton pattern.[15]

traitWitness{typeTvalvalue:T{}}

The above traitWitness declares the memberT, which can be assigned atype as its value, and the membervalue, which can be assigned a value of typeT.The following program text defines an objectbooleanWitness as instance of the above traitWitness.The objectbooleanWitness defines the typeT asBoolean and the valuevalue astrue.For example, executingSystem.out.println(booleanWitness.value) printstrue on the console.

objectbooleanWitnessextendsWitness{typeT=Booleanvalvalue=true}

Letx:σ{\displaystyle \langle {\textsf {x}}:\sigma \rangle } be the type (specifically, arecord type) of objects having the memberx{\displaystyle {\textsf {x}}} of typeσ{\displaystyle \sigma }.In the above example, the objectbooleanWitness can be assigned the dependent intersection type(x:T:Type)value:x.T{\displaystyle (x:\langle {\textsf {T}}:{\text{Type}}\rangle )\cap \langle {\textsf {value}}:x.{\textsf {T}}\rangle }.The reasoning is as follows. The objectbooleanWitness has the memberT that is assigned the typeBoolean as its value.SinceBoolean is a type, the objectbooleanWitness has the typeT:Type{\displaystyle \langle {\textsf {T}}:{\text{Type}}\rangle }.Additionally, the objectbooleanWitness has the membervalue that is assigned the valuetrue of typeBoolean.Since the value ofbooleanWitness.T isBoolean, the objectbooleanWitness has the typevalue:booleanWitness.T{\displaystyle \langle {\textsf {value}}:{\textsf {booleanWitness.T}}\rangle }.Overall, the objectbooleanWitness has the intersection typeT:Typevalue:booleanWitness.T{\displaystyle \langle {\textsf {T}}:{\text{Type}}\rangle \cap \langle {\textsf {value}}:{\textsf {booleanWitness.T}}\rangle }.Therefore, presenting self-reference as dependency, the objectbooleanWitness has the dependent intersection type(x:T:Type)value:x.T{\displaystyle (x:\langle {\textsf {T}}:{\text{Type}}\rangle )\cap \langle {\textsf {value}}:x.{\textsf {T}}\rangle }.

Alternatively, the above minimalistic example can be described usingdependent record types.[16]In comparison to dependent intersection types, dependent record types constitute a strictly more specialized type theoretic concept.[12]

Intersection of a type family

[edit]

Anintersection of a type family, denotedx:στ{\textstyle \bigcap _{x:\sigma }\tau }, is adependent type in which the typeτ{\displaystyle \tau } may depend on the term variablex{\displaystyle x}. In particular, if a termM{\displaystyle M} has the typex:στ{\textstyle \bigcap _{x:\sigma }\tau }, then foreach termN{\displaystyle N} of typeσ{\displaystyle \sigma }, the termM{\displaystyle M} has the typeτ[x:=N]{\displaystyle \tau [x:=N]}. This notion is also calledimplicitPi type,[17] observing that the argumentN{\displaystyle N} is not kept at term level.

Comparison of languages with intersection types

[edit]
LanguageActively developedParadigm(s)StatusFeatures
C#Yes[18]Under discussion[19]Additionally, generic type parameters can have constraints that require their (monomorphized) type-arguments to implement multiple interfaces, whereupon the runtime type represented by the generic type parameter becomes an intersection-type of all listed interfaces.
CeylonNo[20]Supported[21]
  • Type refinement
  • Interface composition
  • Subtyping in width
F#Yes[22]Under discussion[23]?
FlowYes[24]Supported[25]
  • Type refinement
  • Interface composition
ForsytheNoSupported[26]
  • Function type intersection
  • Distributive, co- and contravariant function type subtyping
JavaYes[27]Supported[28]
  • Type refinement
  • Interface composition
  • Subtyping in width
PHPYes[29]Supported[30]
  • Type refinement
  • Interface composition
ScalaYes[31]Supported[32][33]
  • Type refinement
  • Trait composition
  • Subtyping in width
TypeScriptYes[34]Supported[6]
  • Arbitrary type intersection
  • Interface composition
  • Subtyping in width and depth
WhileyYes[35]Supported[36]?

References

[edit]
  1. ^Barendregt, Henk; Coppo, Mario;Dezani-Ciancaglini, Mariangiola (1983). "A filter lambda model and the completeness of type assignment".Journal of Symbolic Logic.48 (4):931–940.doi:10.2307/2273659.JSTOR 2273659.S2CID 45660117.
  2. ^Palsberg, Jens (2012). "Overloading is NP-Complete".Logic and Program Semantics. Lecture Notes in Computer Science. Vol. 7230. pp. 204–218.doi:10.1007/978-3-642-29485-3_13.ISBN 978-3-642-29484-6.
  3. ^Henk Barendregt; Wil Dekkers; Richard Statman (20 June 2013).Lambda Calculus with Types. Cambridge University Press. pp. 1–.ISBN 978-0-521-76614-2.
  4. ^Ghilezan, Silvia (1996)."Strong normalization and typability with intersection types".Notre Dame Journal of Formal Logic.37 (1):44–52.doi:10.1305/ndjfl/1040067315.
  5. ^Kfoury, A.J.; Wells, J.B. (January 2004). "Principality and type inference for intersection types using expansion variables".Theoretical Computer Science:1–70.
  6. ^ab"Intersection Types in TypeScript". Retrieved2019-08-01.
  7. ^Giuseppe Castagna, Programming with Union, Intersection, and Negation Types,https://arxiv.org/pdf/2111.03354 p. 7 Also chapter 12 in "The French School of Programming", Springer 2024, ISBN 978-3-031-34517-3
  8. ^Wells, J.B. (2003). "The Essence of Principal Typings".ICALP '02: Proceedings of the 29th International Colloquium on Automata, Languages and Programming. pp. 913–925.
  9. ^Damiani, Ferruccio. "Rank 2 intersection types for modules".PPDP '03: Proceedings of the 5th ACM SIGPLAN international conference on Principles and practice of declarative programming.
  10. ^Castagna, Giuseppe; Lanvin, Victor. "Gradual Typing with Union and Intersection Types".ICFP 2017.
  11. ^Giuseppe Castagna, Mickaël Laurent, Kim Nguyễn, Polymorphic Type Inference for Dynamic Languages, Proceedings of the ACM on Programming Languages (POPL) 2024, p. 40:6
  12. ^abKopylov, Alexei (2003). "Dependent intersection: A new way of defining records in type theory".18th IEEE Symposium on Logic in Computer Science. LICS 2003. IEEE Computer Society. pp. 86–95.CiteSeerX 10.1.1.89.4223.doi:10.1109/LICS.2003.1210048.
  13. ^"Type declarations in Scala". Retrieved2019-08-15.
  14. ^Amin, Nada; Grütter, Samuel; Odersky, Martin; Rompf, Tiark; Stucki, Sandro (2016). "The Essence of Dependent Object Types".A List of Successes That Can Change the World(PDF). Lecture Notes in Computer Science. Vol. 9600. Springer. pp. 249–272.doi:10.1007/978-3-319-30936-1_14.ISBN 978-3-319-30935-4.
  15. ^"Singletons in the Scala shapeless library".GitHub. Retrieved2019-08-15.
  16. ^Pollack, Robert (2000). "Dependently typed records for representing mathematical structure".Theorem Proving in Higher Order Logics, 13th International Conference. TPHOLs 2000. Springer. pp. 462–479.doi:10.1007/3-540-44659-1_29.
  17. ^Stump, Aaron (2018)."From realizability to induction via dependent intersection".Annals of Pure and Applied Logic.169 (7):637–655.doi:10.1016/j.apal.2018.03.002.
  18. ^"C# Guide". Retrieved2019-08-08.
  19. ^"Discussion: Union and Intersection types in C Sharp".GitHub. Retrieved2019-08-08.
  20. ^"Eclipse Ceylon™". 19 July 2017. Retrieved2023-08-16.
  21. ^"Intersection Types in Ceylon". 19 July 2017. Retrieved2019-08-08.
  22. ^"F# Software Foundation". Retrieved2019-08-08.
  23. ^"Add Intersection Types to F Sharp".GitHub. Retrieved2019-08-08.
  24. ^"Flow: A Static Type Checker for JavaScript". Archived fromthe original on 2022-04-08. Retrieved2019-08-08.
  25. ^"Intersection Type Syntax in Flow". Retrieved2019-08-08.
  26. ^Reynolds, J. C. (1988). Preliminary design of the programming language Forsythe.
  27. ^"Java Software". Retrieved2019-08-08.
  28. ^"IntersectionType (Java SE 12 & JDK 12)". Retrieved2019-08-01.
  29. ^"php.net".
  30. ^"PHP.Watch - PHP 8.1: Intersection Types".
  31. ^"The Scala Programming Language". Retrieved2019-08-08.
  32. ^"Compound Types in Scala". Retrieved2019-08-01.
  33. ^"Intersection Types in Dotty". Retrieved2019-08-01.
  34. ^"TypeScript - JavaScript that scales". Retrieved2019-08-01.
  35. ^"Whiley: an Open Source Programming Language with Extended Static Checking". Retrieved2019-08-01.
  36. ^"Whiley language specification"(PDF). Archived fromthe original(PDF) on 2020-01-16. Retrieved2019-08-01.
Uninterpreted
Numeric
Pointer
Text
Composite
Other
Related
topics
Retrieved from "https://en.wikipedia.org/w/index.php?title=Intersection_type&oldid=1320567532"
Categories:
Hidden categories:

[8]ページ先頭

©2009-2025 Movatter.jp