Glispは構文上型と値を区別しない。

たとえば、TypeScriptではある型Tからなる配列型をT[]と表現する。これは通常の値からは区別された文法を持ち、値が置かれる場所にconst Atrr = T[]のように型を置くことができない。型と値は名前空間も独立しており、文法要素として直交している。これは、トランスコンパイルすることで型情報を削ぎ落とし、JavaScriptとして実行されることを想定されているがゆえの要請。

Glispでは極力実装や文法をシンプルにしたかったので、こうした区別をつけないこととした。すべての値は型であり、すべての型は値として使うことができる。

リストとタプル

TypeScript、Haskellなど多くの言語は、リスト型とタプル型を区別する。Glispではいずれも、「末尾の要素を可変長にできるタプル型」として統合して扱う。

(TypeScript) -> (Glisp)
T[] -> [...T]
[T, U] -> [T U]
[T, ...U] -> [T ...U]

こういう時に不便なのでは?

おそらくは2個以上要素のあるであろう配列をタプルにキャプチャしたい時。rangeが返すであろうタプルの要素数を明示しないといけないので不便。rangeはまだ返すであろう要素数の計算が簡単でも、「指定範囲間の素数からなるリストを返す」なんてケースだと、型推論の計算コストが評価時の計算コストと同等になってしまう。

[a b] = (take 2 (range 0 100))
;; 右辺の型は [...Int] のため、左辺にマッチしない

特例として、可変長タプル <: 固定長タプル という形の部分型判定は、固定長部分の要素数に依らず真とする。個数が足りるかどうかは実行時に判定し、足りない要素はボトムで埋める。

[o o] <: [o]  ; 固定長タプル同士は、要素数が同か多い方が部分型
[o o] <: [o ...o] ; タプル <: 可変長タプル の場合も固定長部分を比較する
[o ...o] <: [o ...o] ;これも真
[...o] <: [o o]  ; 可変長 <: タプル の場合の場合、

これ、結局タプルとリストを区別する普通の言語に戻っとりませんか?

あとこの場合


(match t ;; 型は [...T], 実際の値は []
	[x] ... ;; ここにマッチしてしまう
  _ ...) ;; 本当はここにマッチして欲しいのに

のようになりかねない

いや、そもそもこのケースはmatch構文で場合分けするべきじゃない。

TypeScriptの挙動

type T = number
// Source has 3 element(s) but target allows only 2.
const v0: [T, T] = [1, 2, 3]
// OK
const [v0a, v0b] = [1, 2, 3]
// Type '[number, number, number]' is not assignable to type '[number, number]'
const [v0c, v0d]: [T, T] = [1, 2, 3]
// OK
const v1: [T, T] = [1, 2]
// Source has 1 element(s) but target requires 2.
const v2: [T, T] = [1]
// Target requires 2 element(s) but source may have fewer.
const v3: [T, T] = Array.of(1)
// Target allows only 2 element(s) but source may have more.
const v4: [T, T] = [1, 2, ...Array.of(1)]
// OK
const v5: [T, T] = Array.of(1) as [T, T]
// inferred as number[]
const v6 = [1, 2, ...Array.of(1)]