Merge branch 'main' into pr/212

This commit is contained in:
Shunsuke Shibayama 2022-11-13 19:57:20 +09:00
commit a4d5b09df9
14 changed files with 242 additions and 114 deletions

View file

@ -753,6 +753,9 @@ impl PyCodeGenerator {
} }
fn cancel_if_pop_top(&mut self) { fn cancel_if_pop_top(&mut self) {
if self.cur_block_codeobj().code.len() < 2 {
return;
}
let lasop_t_idx = self.cur_block_codeobj().code.len() - 2; let lasop_t_idx = self.cur_block_codeobj().code.len() - 2;
if self.cur_block_codeobj().code.get(lasop_t_idx) == Some(&(POP_TOP as u8)) { if self.cur_block_codeobj().code.get(lasop_t_idx) == Some(&(POP_TOP as u8)) {
self.mut_cur_block_codeobj().code.pop(); self.mut_cur_block_codeobj().code.pop();
@ -1495,7 +1498,7 @@ impl PyCodeGenerator {
} else { } else {
// no else block // no else block
let idx_end = if self.py_version.minor >= Some(11) { let idx_end = if self.py_version.minor >= Some(11) {
self.lasti() - idx_pop_jump_if_false self.lasti() - idx_pop_jump_if_false - 1
} else { } else {
self.lasti() self.lasti()
}; };
@ -2376,14 +2379,15 @@ impl PyCodeGenerator {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
let line = sig.ln_begin().unwrap(); let line = sig.ln_begin().unwrap();
let class_name = sig.ident().inspect(); let class_name = sig.ident().inspect();
let ident = Identifier::public_with_line(DOT, Str::ever("__init__"), line); let mut ident = Identifier::public_with_line(DOT, Str::ever("__init__"), line);
ident.vi.t = __new__.clone();
let param_name = fresh_varname(); let param_name = fresh_varname();
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line); let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None); let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let self_param = VarName::from_str_and_line(Str::ever("self"), line); let self_param = VarName::from_str_and_line(Str::ever("self"), line);
let self_param = NonDefaultParamSignature::new(ParamPattern::VarName(self_param), None); let self_param = NonDefaultParamSignature::new(ParamPattern::VarName(self_param), None);
let params = Params::new(vec![self_param, param], None, vec![], None); let params = Params::new(vec![self_param, param], None, vec![], None);
let subr_sig = SubrSignature::new(ident, params, __new__.clone()); let subr_sig = SubrSignature::new(ident, params);
let mut attrs = vec![]; let mut attrs = vec![];
match __new__.non_default_params().unwrap()[0].typ() { match __new__.non_default_params().unwrap()[0].typ() {
// namedtupleは仕様上::xなどの名前を使えない // namedtupleは仕様上::xなどの名前を使えない
@ -2431,11 +2435,12 @@ impl PyCodeGenerator {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
let class_ident = sig.ident(); let class_ident = sig.ident();
let line = sig.ln_begin().unwrap(); let line = sig.ln_begin().unwrap();
let ident = Identifier::public_with_line(DOT, Str::ever("new"), line); let mut ident = Identifier::public_with_line(DOT, Str::ever("new"), line);
ident.vi.t = __new__;
let param_name = fresh_varname(); let param_name = fresh_varname();
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line); let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None); let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let sig = SubrSignature::new(ident, Params::new(vec![param], None, vec![], None), __new__); let sig = SubrSignature::new(ident, Params::new(vec![param], None, vec![], None));
let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line( let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line(
Str::from(param_name), Str::from(param_name),
line, line,

View file

@ -3,7 +3,7 @@ use std::option::Option; // conflicting to Type::Option
use erg_common::error::MultiErrorDisplay; use erg_common::error::MultiErrorDisplay;
use crate::ty::constructors::{and, or}; use crate::ty::constructors::{and, or, poly};
use crate::ty::free::fresh_varname; use crate::ty::free::fresh_varname;
use crate::ty::free::{Constraint, FreeKind}; use crate::ty::free::{Constraint, FreeKind};
use crate::ty::typaram::{OpKind, TyParam, TyParamOrdering}; use crate::ty::typaram::{OpKind, TyParam, TyParamOrdering};
@ -848,6 +848,35 @@ impl Context {
let t = self.into_refinement(t.clone()); let t = self.into_refinement(t.clone());
Type::Refinement(self.union_refinement(&t, r)) Type::Refinement(self.union_refinement(&t, r))
} }
// Array({1, 2}, 2), Array({3, 4}, 2) ==> Array({1, 2, 3, 4}, 2)
(
Type::Poly {
name: ln,
params: lps,
},
Type::Poly {
name: rn,
params: rps,
},
) if ln == rn => {
debug_assert_eq!(lps.len(), rps.len());
let mut unified_params = vec![];
for (lp, rp) in lps.iter().zip(rps.iter()) {
match (lp, rp) {
(TyParam::Type(l), TyParam::Type(r)) => {
unified_params.push(TyParam::t(self.union(l, r)))
}
(_, _) => {
if self.eq_tp(lp, rp) {
unified_params.push(lp.clone());
} else {
return or(lhs.clone(), rhs.clone());
}
}
}
}
poly(ln, unified_params)
}
(l, r) => or(l.clone(), r.clone()), (l, r) => or(l.clone(), r.clone()),
} }
} }

View file

@ -686,8 +686,11 @@ impl Context {
self.deref_tyvar(mem::take(var.ref_mut_t()), Covariant, var.loc())?; self.deref_tyvar(mem::take(var.ref_mut_t()), Covariant, var.loc())?;
} }
hir::Signature::Subr(subr) => { hir::Signature::Subr(subr) => {
subr.t = *subr.ref_mut_t() = self.deref_tyvar(
self.deref_tyvar(mem::take(&mut subr.t), Covariant, subr.loc())?; mem::take(subr.ref_mut_t()),
Covariant,
subr.loc(),
)?;
} }
} }
for chunk in attr.body.block.iter_mut() { for chunk in attr.body.block.iter_mut() {
@ -738,8 +741,11 @@ impl Context {
self.deref_tyvar(mem::take(var.ref_mut_t()), Covariant, var.loc())?; self.deref_tyvar(mem::take(var.ref_mut_t()), Covariant, var.loc())?;
} }
hir::Signature::Subr(subr) => { hir::Signature::Subr(subr) => {
subr.t = *subr.ref_mut_t() = self.deref_tyvar(
self.deref_tyvar(mem::take(&mut subr.t), Covariant, subr.loc())?; mem::take(subr.ref_mut_t()),
Covariant,
subr.loc(),
)?;
} }
} }
for chunk in def.body.block.iter_mut() { for chunk in def.body.block.iter_mut() {

View file

@ -437,6 +437,11 @@ impl Identifier {
self.name.inspect() self.name.inspect()
} }
/// show dot + name (no qual_name & type)
pub fn show(&self) -> String {
format!("{}{}", fmt_option!(self.dot), self.name)
}
pub fn is_procedural(&self) -> bool { pub fn is_procedural(&self) -> bool {
self.name.is_procedural() self.name.is_procedural()
} }
@ -1366,22 +1371,45 @@ impl Params {
pub struct SubrSignature { pub struct SubrSignature {
pub ident: Identifier, pub ident: Identifier,
pub params: Params, pub params: Params,
pub t: Type,
} }
impl NestedDisplay for SubrSignature { impl NestedDisplay for SubrSignature {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "{}{} (: {})", self.ident, self.params, self.t,) write!(
f,
"{}{} (: {})",
self.ident.show(),
self.params,
self.ident.t()
)
} }
} }
impl_display_from_nested!(SubrSignature); impl_display_from_nested!(SubrSignature);
impl_locational!(SubrSignature, ident, params); impl_locational!(SubrSignature, ident, params);
impl_t!(SubrSignature);
impl HasType for SubrSignature {
#[inline]
fn ref_t(&self) -> &Type {
self.ident.ref_t()
}
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
self.ident.ref_mut_t()
}
#[inline]
fn signature_t(&self) -> Option<&Type> {
self.ident.signature_t()
}
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
self.ident.signature_mut_t()
}
}
impl SubrSignature { impl SubrSignature {
pub const fn new(ident: Identifier, params: Params, t: Type) -> Self { pub const fn new(ident: Identifier, params: Params) -> Self {
Self { ident, params, t } Self { ident, params }
} }
pub fn is_procedural(&self) -> bool { pub fn is_procedural(&self) -> bool {

View file

@ -988,8 +988,9 @@ impl ASTLowerer {
id, id,
found_body_t, found_body_t,
)?; )?;
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name); let mut ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, params, t); ident.vi.t = t;
let sig = hir::SubrSignature::new(ident, params);
let body = hir::DefBody::new(body.op, block, body.id); let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body)) Ok(hir::Def::new(hir::Signature::Subr(sig), body))
} }
@ -1019,7 +1020,7 @@ impl ASTLowerer {
); );
let block = self.lower_block(body.block)?; let block = self.lower_block(body.block)?;
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name); let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, params, Type::Failure); let sig = hir::SubrSignature::new(ident, params);
let body = hir::DefBody::new(body.op, block, body.id); let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body)) Ok(hir::Def::new(hir::Signature::Subr(sig), body))
} }

View file

@ -273,7 +273,14 @@ impl Parser {
chunks.push(expr); chunks.push(expr);
} }
} }
None => switch_unreachable!(), None => {
if !self.errs.is_empty() {
self.level -= 1;
return Err(());
} else {
switch_unreachable!()
}
}
} }
} }
self.level -= 1; self.level -= 1;

View file

@ -29,14 +29,27 @@ That is, expressions such as `X**2 - 5X + 6 == 0` cannot be used as refinement-t
If you know how to solve quadratic equations, you would expect the above refinement form to be equivalent to `{2, 3}`. If you know how to solve quadratic equations, you would expect the above refinement form to be equivalent to `{2, 3}`.
However, the Erg compiler has very little knowledge of algebra, so it cannot solve the predicate on the right. However, the Erg compiler has very little knowledge of algebra, so it cannot solve the predicate on the right.
## Subtyping rules for refinement types
All refinement types are subtypes of the type specified in the `Type` part.
```erg
{I: Int | I <= 0} <: Int
```
Otherwise, the current Erg has a subtyping type rule for integer comparisons.
```erg
{I: Int | I <= 5} <: {I: Int | I <= 0}
```
## Smart Cast ## Smart Cast
It's nice that you defined `Odd`, but as it is, it doesn't look like it can be used much outside of literals. To promote an odd number in a normal `Int` object to `Odd`, i.e., to downcast an `Int` to `Odd`, you need to pass the constructor of `Odd`. It's nice that you defined `Odd`, but as it is, it doesn't look like it can be used much outside of literals. To promote an odd number in a normal `Int` object to `Odd`, i.e., to downcast an `Int` to `Odd`, you need to pass the constructor of `Odd`.
For refinement types, the normal constructor `.new` may panic, and there is an auxiliary constructor called `.try_new` that returns a `Result` type. For refinement types, the normal constructor `.new` may panic, and there is an auxiliary constructor called `.try_new` that returns a `Result` type.
```python ```python
i = Odd.new (0..10).sample!() i = Odd.new (0..10).sample!() # i: Odd (or Panic)
i: Odd # or Panic
``` ```
It can also be used as a type specification in `match`. It can also be used as a type specification in `match`.

View file

@ -2,6 +2,8 @@
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/API/funcs.md%26commit_hash%3D06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/funcs.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352) [![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/API/funcs.md%26commit_hash%3D06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/funcs.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
> __Note__: `match`は関数ではなく特殊形式です。
## 基本関数 ## 基本関数
### if|T; U|(cond: Bool, then: T, else: U) -> T or U ### if|T; U|(cond: Bool, then: T, else: U) -> T or U

View file

@ -53,46 +53,21 @@ if True, do:
無名プロシージャ、プロシージャ型を生成する。 無名プロシージャ、プロシージャ型を生成する。
## `:`(subject, T)
subjectがTに合致しているか判定する。合致していない場合はコンパイルエラーを送出する。
```python
a: Int
f x: Int, y: Int = x / y
```
また、`:`適用スタイルにも使われる。
```python
f x:
y
z
```
`:``=`と同じく演算の結果が未定義である。
```python
_ = x: Int # SyntaxError:
print!(x: Int) # SyntaxError:
```
## `.`(obj, attr) ## `.`(obj, attr)
objの属性を読み込む。 objの属性を読み込む。
`x.[y, z]`とすると、xのyとzという属性を配列にして返す。
## `|>`(obj, c: Callable) ## `|>`(obj, c: Callable)
`c(obj)`を実行する。`x + y |>.foo()``(x + y).foo()`と同じ。 `c(obj)`を実行する。`x + y |>.foo()``(x + y).foo()`と同じ。
### (x: Option T)`?` -> T | T ### (x: Option T)`?` -> T
後置演算子。`x.unwrap()`を呼び出し、エラーの場合はその場で`return`する。 後置演算子。`x.unwrap()`を呼び出し、エラーの場合はその場で`return`する。
## match(obj, ...lambdas: Lambda) ## match(obj, ...arms: Lambda)
objについて、パターンにマッチしたlambdaを実行する objについて、パターンにマッチしたarmを実行する。armは無名関数でなくてはならない。
```python ```python
match [1, 2, 3]: match [1, 2, 3]:
@ -102,15 +77,25 @@ match [1, 2, 3]:
# (1, 2, 3) # (1, 2, 3)
``` ```
## del(x: ...T) -> NoneType | T 型指定によって処理を分岐できるが、型推論の結果は分岐に影響しない。
```python
zero: {0} -> {0}
one: {1} -> {1}
_ = match x:
i -> zero i
j -> one j # Warning: cannot reach this arm
```
## Del(x: ...T) -> NoneType
変数`x`を削除する。ただし組み込みのオブジェクトは削除できない。 変数`x`を削除する。ただし組み込みのオブジェクトは削除できない。
```python ```python
a = 1 a = 1
del a # OK Del a # OK
del True # SyntaxError: cannot delete a built-in object Del True # SyntaxError: cannot delete a built-in object
``` ```
## do(body: Body) -> Func ## do(body: Body) -> Func
@ -149,7 +134,7 @@ assert True.then(choice) == 1
### `{}`(layout, ...names, ...preds) ### `{}`(layout, ...names, ...preds)
篩型、ランク2型を生成する。 篩型を生成する。
### `...` ### `...`
@ -169,10 +154,10 @@ assert {x; ...yz} == {x = 1; y = 2; z = 3}
ユーザーが直接使用できない演算子です。 ユーザーが直接使用できない演算子です。
### ref(x: T) -> Ref T | T ### ref(x: T) -> Ref T
オブジェクトの不変参照を返す。 オブジェクトの不変参照を返す。
### ref!(x: T!) -> Ref! T! | T! ### ref!(x: T!) -> Ref! T!
可変オブジェクトの可変参照を返す。 可変オブジェクトの可変参照を返す。

View file

@ -8,13 +8,13 @@
基本的に、すべてのパターンは「平坦化」される。具体的には、 基本的に、すべてのパターンは「平坦化」される。具体的には、
``` ```erg
[i, [j, k]] -> ... [i, [j, k]] -> ...
``` ```
は、 は、
``` ```erg
%1 -> %1 ->
i = %1[0] i = %1[0]
%2 = %1[1] %2 = %1[1]
@ -46,7 +46,7 @@ Typeが篩型(e.g. `{I: Int | I >= 0}`)の場合は、中の述語式を評価
`F(X)`型の検査を考える。定義が`F(A <-> E) = ...`(`E`中に現れる`Self`はオブジェクト自身に置換される)であるとき、`fits(X, E)`で検査される。 `F(X)`型の検査を考える。定義が`F(A <-> E) = ...`(`E`中に現れる`Self`はオブジェクト自身に置換される)であるとき、`fits(X, E)`で検査される。
``` ```erg
fits X, E = fits X, E =
if Typeof(X) == Type: if Typeof(X) == Type:
then := do subtypeof X, E then := do subtypeof X, E
@ -55,7 +55,7 @@ fits X, E =
`Array`の定義は `Array`の定義は
``` ```erg
Array T <-> Union Self.iter().map(Typeof), N <-> Self.__len__() = ... Array T <-> Union Self.iter().map(Typeof), N <-> Self.__len__() = ...
``` ```
@ -79,55 +79,69 @@ match x:
match x: match x:
_: {1} -> log "one" _: {1} -> log "one"
_: {"a"} -> log "a" _: {"a"} -> log "a"
_: Obj -> log "other" _ -> log "other"
``` ```
Ergの型付けは基本的にextrinsic(外在的)であり、型を消去したコードも動的には実行できる(型なしで項が意味を持ちうる)。これは、ErgがPythonとの相互運用性を企図して設計されているためである。 Ergの型は基本的にextrinsic(外在的)であり、型を消去したコードも動的には実行できる(型なしで項が意味を持ちうる)。これは、ErgがPythonとの相互運用性を企図して設計されているためである。
しかしパターンマッチにおいては、Ergの型はintrinsic(内在的)であるといえる。型によって処理が変わるため、型消去したコードは最早実行できない。 しかしパターンマッチにおいては、Ergの型はintrinsic(内在的)であるといえる。型指定自体がパターンの一つであり、型によって処理が変わるため、型消去したコードは最早実行できない。
## 配列・タプルパターン ## タプルパターン
```erg
(True, 1) -> ...
``` ```
```erg
%1: ({True}, {1}) ->
_ = %1[0]
_ = %1[1]
...
```
## 配列パターン
配列は型情報が平坦化されてしまうので、一工夫が必要である。具体的には、篩型を使う。
```erg
[[True, False], [True, True]] -> ... [[True, False], [True, True]] -> ...
``` ```
``` ```erg
%1 -> %1: {I: ? | } ->
%2 = %1[0]
_: {True} = %2[0]
_: {False} = %2[1]
%3 = %1[1]
_: {True} = %3[0]
_: {True} = %3[1]
... ...
``` ```
全ての変数の型を推論すると
```
%1: [[{True}, {False}], [{True}, {True}]] ->
%2 [{True}, {False}] = %1[0]
_: {True} = %2[0]
_: {False} = %2[1]
%3: [{True}, {True}] = %1[1]
_: {True} = %3[0]
_: {True} = %3[1]
...
```
コンパイルする場合は、`%1[0] == True and %1[1] == False and ...`というように、配列の要素を直接比較することになる。
```
[True, False, i] -> ...
%1: [{True}, {False}, Obj] ->
_: {True} = %1[0] ```erg
_: {False} = %1[1] %1: {I: [[_; ?]; ?] | } ->
i = %1[2] %2 = %1[0]
... ...
``` ```
バイトコードでの検査は`%1`の各要素に対してこれまでに見た検査を行い、`and`を取る。
`_: {True}`なら`_ == True``i`は検査なしで束縛するから、`%1[0] == True and %1[1] == False`というようになる。
```erg
%1: {I: [[_; 2]; ?] | I[0][0] == True and I[0][1] == False} ->
%2 = %1[0]
_ = %2[0]
_ = %2[1]
...
```
```erg
%1: {I: [[_; 2]; 2] | I[0][0] == True and I[0][1] == False and I[1][0] == True and I[1][1] == True} ->
%2 = %1[0]
_ = %2[0]
_ = %2[1]
%3 = %1[1]
_ = %3[0]
_ = %3[1]
...
```

View file

@ -9,23 +9,19 @@
```python ```python
# 基本的な代入 # 基本的な代入
i = 1 i = 1
# 型つき
i: Int = 1
# 無名型つき
i: {1, 2, 3} = 2
# function # function
fn x = x + 1 fn x = x + 1
# equals
fn x: Add(Int) = x + 1
# (無名)関数 # (無名)関数
fn = x -> x + 1 fn = x -> x + 1
fn: Int -> Int = x -> x + 1 ```
# 上位型 ## 型宣言パターン
a: [Int; 4] = [0, 1, 2, 3]
# もしくは ```
a: Array Int, 4 = [0, 1, 2, 3] i: Int = 1
j: {1, 2, 3} = 2
(k: Int, s: Str) = 1, "a"
``` ```
### リテラルパターン ### リテラルパターン

View file

@ -4,8 +4,8 @@
Refinement type(篩型、ふるいがた)は、述語式によって制約付けられた型です。列挙型や区間型は篩型の一種です。 Refinement type(篩型、ふるいがた)は、述語式によって制約付けられた型です。列挙型や区間型は篩型の一種です。
篩型の標準形は`{Elem: Type | (Pred)*}`です。これは、`Pred`を満たす`Elem`を要素とする型である、という意味です。 篩型の標準形は`{Elem: Type | (Pred)*}`です。これは、述語式`Pred`を満たす`Elem`を要素とする型である、という意味です。
篩型に使えるのは[Value型](./08_value.md)のみです。 `Type`に使えるのは[Value型](./08_value.md)のみです。
```python ```python
Nat = 0.._ Nat = 0.._
@ -31,14 +31,27 @@ Array3OrMore == {A: Array _, N | N >= 3}
あなたが二次方程式の解法を知っているならば、上の篩型は`{2, 3}`と同等になるだろうと予想できるはずです。 あなたが二次方程式の解法を知っているならば、上の篩型は`{2, 3}`と同等になるだろうと予想できるはずです。
しかしErgコンパイラは代数学の知識をほとんど持ち合わせていないので、右の述語式を解決できないのです。 しかしErgコンパイラは代数学の知識をほとんど持ち合わせていないので、右の述語式を解決できないのです。
## 篩型の部分型付け規則
全ての篩型は、`Type`部で指定された型の部分型です。
```erg
{I: Int | I <= 0} <: Int
```
その他、現在のErgは整数の比較に関する部分型規則を持っています。
```erg
{I: Int | I <= 5} <: {I: Int | I <= 0}
```
## スマートキャスト ## スマートキャスト
`Odd`を定義したのはいいですが、このままではリテラル以外ではあまり使えないようにみえます。通常の`Int`オブジェクトの中の奇数を`Odd`に昇格させる、つまり`Int``Odd`にダウンキャストするためには、`Odd`のコンストラクタを通す必要があります。 `Odd`を定義したのはいいですが、このままではリテラル以外ではあまり使えないようにみえます。通常の`Int`オブジェクトの中の奇数を`Odd`に昇格させる、つまり`Int``Odd`にダウンキャストするためには、`Odd`のコンストラクタを通す必要があります。
篩型の場合、通常のコンストラクタ`.new`はパニックする可能性があり、`.try_new`という`Result`型を返す補助的なコンストラクタもあります。 篩型の場合、通常のコンストラクタ`.new`はパニックする可能性があり、`.try_new`という`Result`型を返す補助的なコンストラクタもあります。
```python ```python
i = Odd.new (0..10).sample!() i = Odd.new (0..10).sample!() # i: Odd (or Panic)
i: Odd # or Panic
``` ```
また、`match`中で型指定として使用することもできます。 また、`match`中で型指定として使用することもできます。
@ -73,8 +86,9 @@ match i:
```python ```python
# メソッド.mは長さ3以上の配列に定義される # メソッド.mは長さ3以上の配列に定義される
Array(T, N | N >= 3) Array(T, N | N >= 3)
.m(&self) = ... .m(ref self) = ...
``` ```
<p align='center'> <p align='center'>
<a href='./11_enum.md'>Previous</a> | <a href='./13_algebraic.md'>Next</a> <a href='./11_enum.md'>Previous</a> | <a href='./13_algebraic.md'>Next</a>
</p> </p>

View file

@ -74,6 +74,36 @@ MyArray(T, N) = Inherit [T; N]
# .arrayと連動してself: Self(T, N)の型が変わる # .arrayと連動してself: Self(T, N)の型が変わる
MyStruct!(T, N: Nat!) = Class {.array: [T; !N]} MyStruct!(T, N: Nat!) = Class {.array: [T; !N]}
``` ```
## 実体指定
動的配列`arr: [T; !N]`について、処理を進めていくうちに`N`の情報が失われてしまったとします。
この情報は`assert arr.__len__() == X`とすることで回復させることができます。
```erg
arr: [Int; !_]
assert arr.__len__() == 3
arr: [Int; !3]
```
これは型パラメータの __実体指定__ によって可能となっています。配列型`Array(T, N)`は以下のように定義されています。
```erg
Array T <-> Union Self.map(x -> Typeof x), N <-> Self.__len__() = ...
```
`<->`は依存型のパラメータのみで使える特別な記号で、そのパラメータに対する実体を指示します。実体であるところの右辺式は、コンパイル時に計算可能でなくても構いません。コンパイル時情報である`N`と実行時情報である`Self.__len__()`が実体指定を通してリンクされる訳です。
実体指定に沿った方法でassertionが行われると、型パラメータの情報が復活します。すなわち、`assert arr.__len__() == N`とすると`N`の情報が復活します。ただしこの場合の`N`はコンパイル時計算可能でなくてはなりません。
実体指定は`assert`以外に`match`でも活用されます。
```erg
arr: [Obj; _]
match! arr:
pair: [Obj; 2] => ...
ints: [Int; _] => ...
_ => ...
```
<p align='center'> <p align='center'>
<a href='./13_algebraic.md'>Previous</a> | <a href='./15_quantified.md'>Next</a> <a href='./13_algebraic.md'>Previous</a> | <a href='./15_quantified.md'>Next</a>
</p> </p>

View file

@ -155,9 +155,7 @@ impl Runnable for DummyVM {
.to_string(), .to_string(),
); );
if let Some(Expr::Def(def)) = last { if let Some(Expr::Def(def)) = last {
res.push_str(&format!(" ({}: ", def.sig.ident())); res.push_str(&format!(" ({})", def.sig.ident()));
res.push_str(&def.sig.t().to_string());
res.push(')');
} }
} }
Ok(res) Ok(res)