# モジュール

[![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/syntax/26_module.md%26commit_hash%3Dc8932f8fd75cc86f67421bb6b160fffaf7acdd94)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/26_module.md&commit_hash=c8932f8fd75cc86f67421bb6b160fffaf7acdd94)

Ergでは、ファイル自体を1つのレコードとみなすことができます[<sup id="f1">1</sup>](#1)。これをモジュールと呼びます。

```python,checker_ignore
# foo.er
.i = 1
```

```python
# fooモジュールを定義するのはこのレコードを定義するのと構造的には同じ
foo = {.i = 1}
```

```python,checker_ignore
# bar.er
foo = import "foo"
print! foo # <module 'foo'>
assert foo.i == 1
```

モジュール型は分解代入が可能です。

```python
{sin; cos} = import "math"
```

## モジュールの可視性

ファイルだけでなく、ディレクトリもモジュールとなりえます。
ただしデフォルトでErgはディレクトリをErgモジュールとしては認識しません。認識させるには、`__init__.er`という名前のファイルを作成します。
`__init__.er`はPythonの`__init__.py`と同じようなものです。

```console
└─┬ bar
  └─ __init__.er
```

これで、`bar`ディレクトリはモジュールとして認識されます。`bar`内にあるファイルが`__init__.er`だけならばあまりディレクトリ構造にする意味はありませんが、複数のモジュールを束ねて一つのモジュールとしたい場合は便利です。すなわち、このような場合です。

```console
└─┬ bar
  ├─ __init__.er
  ├─ baz.er
  └─┬ qux
    └─ __init__.er
```

```python
# bar/__init__.er
.baz = import "./baz"
.qux = import "./qux"
```

`bar`ディレクトリの外側からは以下のようにして使用できます。

```python
bar = import "bar"

bar.baz.p!()
bar.qux.p!()
```

`__init__.er`は単にディレクトリをモジュールとして機能させるだけのマーカーではなく、モジュールの可視性を制御する役割も持ちます。
Pythonとは違い、Ergのモジュールはデフォルトではインポートできないようになっています。

```python
# __init__.er

# `./`はカレントディレクトリを指す。なくても良い
.baz = import "./baz"
qux = import "./qux"

.f x =
    .baz.f ...
.g x =
    qux.f ...
```

外から`bar`モジュールをインポートしたとき、`baz`モジュールはアクセス可能ですが、`qux`モジュールはアクセス不可能になります。

## モジュールの循環参照

Ergでは、モジュール間の循環的な依存関係を定義することができます。

```python
# foo.er
bar = import "bar"

print! bar.g 1
.f x = x
```

```python
# bar.er
foo = import "foo"

print! foo.f 1
.g x = x
```

しかし、手続き呼び出しによって作られた変数は、循環参照モジュールで定義することはできません。
これは、Ergが依存関係に従って定義の順番を並べ替えるからです。

```python,compile_fail
# foo.er
bar = import "bar"

print! bar.x
.x = g!(1) # ModuleError: 手続き呼び出しで作られた変数は、循環参照モジュールで定義できない
```

```python
# bar.er
foo = import "foo"

print! foo.x
.x = 0
```

また、エントリポイントであるErgモジュール（すなわち `__name__ == "__main__"` であるモジュール）は循環参照の対象になることはできません。

---

<span id="1" style="font-size:x-small"><sup>1</sup> モジュールとレコードの間に直接の部分型関係はないが、形式的にはモジュールがレコードの部分集合である。レコード内では属性の定義のみが行えるが、モジュール内ではあらゆる可能な式を置ける。[↩](#f1) </span>

<p align='center'>
    <a href='./25_closure.md'>Previous</a> | <a href='./27_object_system.md'>Next</a>
</p>
