Juliaのmodule自由自在

Julia 1.0 のmoduleを使うとき、moduleの中にmoduleをいれたいこともあるだろう。
twitterでこのような話が出ていたので、自分なりの解決方法を示す。
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/Julia%E8%A8%80%E8%AA%9E?src=hash&amp;ref_src=twsrc%5Etfw">#Julia言語</a> 【moduleのnestの仕方】私も知らないのでみんなに質問。<br><br>module A<br><br>f(x) = 2x<br><br>module B<br>import ..A: f<br>g(x) = f(f(x))<br>end<br><br>end<br><br>import .A<br>A.B.g(π)<br>→12.566370614359172<br><br>のような感じにするのが普通なのでしょうか？<br><br>スクショとGist URL紹介に続く<a href="https://t.co/nErF6ROqSV">https://t.co/nErF6ROqSV</a></p>&mdash; 黒木玄 Gen Kuroki (@genkuroki) <a href="https://twitter.com/genkuroki/status/1045451289205780480?ref_src=twsrc%5Etfw">September 27, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



# 解決したいもの

```julia:module.jl
module Level1
    function fire()
        println("fire")
    end
    module Level2
        function firestorm()
            println("storm")
            fire()
        end
        module Level3
            function dragonfire()
                println("dragon")
                firestorm()
                fire()
                println("(^_^)v")
            end
        end
    end
end

using .Level1
Level1.Level2.firestorm()
```
をエラーなく動かしてみたい。上のコードは、

```bash
storm
ERROR: LoadError: UndefVarError: fire not defined
```
とエラーが出る。stormまでは出力されているので、firestorm()の呼び出しはうまくいっている。

なお、

```julia:module.jl
module Level1
    function fire()
        println("fire")
    end
    module Level2
        function firestorm()
            println("storm")
            Level1.fire()
        end
        module Level3
            function dragonfire()
                println("dragon")
                firestorm()
                fire()
                println("(^_^)v")
            end
        end
    end
end
```
としても、同様のエラーが出る。


# Juliaでのmoduleの呼び出しについて
Juliaで自前のmoduleを呼び出すときは、ドット.をつけて.Level1のように呼び出す。
これは、Linuxで言うところの「現在位置./」のようなものと考えればよい。つまり、現在位置「./」にあるLevel1というmoduleを呼び出している。
もし、Level2モジュール内のfirestorm()からLevel1モジュールのfire()を呼び出したいのであれば、「現在位置より一つ上の階層のディレクトリ../」と同じように、..をつければよい。つまり、

```julia:module.jl
module Level1
    function fire()
        println("fire")
    end
    module Level2
        using ..Level1
        function firestorm()
            println("storm")
            Level1.fire()
        end
        module Level3
            using ...Level1
            using ..Level2
            function dragonfire()
                println("dragon")
                Level2.firestorm()
                Level1.fire()
                println("(^_^)v")
            end
        end
    end
end

using .Level1
Level1.Level2.firestorm()
Level1.Level2.Level3.dragonfire()
```
ならfirestorm()はエラーなく呼び出せる。なお、さらに上の階層は...とすればよいので、上のコードでは、Level3からLevel1のfire()を呼び出すことができる。

上のコードは少し煩雑な気もするので、整理することとする。exportをつけたfunctionはいちいちモジュール名をつけなくてよくなるので

```julia:module.jl
module Level1
    export fire,Level2
    function fire()
        println("fire")
    end
    module Level2
        using ..Level1
        export firestorm,Level3
        function firestorm()
            println("storm")
            fire()
        end
        module Level3
            using ...Level1
            using ..Level2
            export dragonfire
            function dragonfire()
                println("dragon")
                firestorm()
                fire()
                println("(^_^)v")
            end
        end
    end
end

using .Level1
using .Level2
using .Level3
firestorm()
dragonfire()
```
と書くことができる。
Level1モジュールのexportにfire()があるのでfireはLevel1と書く必要がなく、Level2もあるので、usingをする際に.Level1.Level2と書く必要がない。また、Level2のexportにfirestormがあるのでLevel2を書く必要がないために、firestormをそのまま呼び出すことができるようになっている。同様に、dragonfireも呼び出せるようになっている。