uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

Elmにおけるimportの使い方

Elmにおけるインポートの方法を説明する。本説明が対応するElmのバージョンはElm 0.14かそれ以降、ただしインポートの仕様は今後大きく変更される可能性がある(今後についての関連情報)。

他モジュールで定義され、エクスポートされた識別子(型コンストラクタ、値コンストラクタ、型エイリアス、定数・関数など)は、インポートすることで始めて使用可能となる。Elmのimportは、この点でJavaのimportと異なっている。Javaではimport宣言をしてもしなくてもFQCNを指定すればクラスパスにあるすべての識別子を参照可能であるが、Elmでは、インポートの明示的な宣言をしない限り、他モジュールの識別子を利用できない(ただし、いくつかのモジュール・識別子はデフォルトでインポートされている。後述)。

インポートの宣言をする方法は大きく分けて2つある。

  • Qualified Import
  • Open Import

(Open Importはunqualified importと呼ばれることもあるようだ)。いずれもソースファイル冒頭(モジュール宣言のすぐ後)に記述する。以降、それぞれについて説明する。

Qualified Import

一般形式:

  1. import モジュール名A
  2. import モジュール階層.モジュール階層.モジュール名B
  3. import モジュール名 as 短縮識別子C
  4. import モジュール階層.モジュール階層.モジュール名 as 短縮識別子D

説明:

Qualified Importは、モジュール指定もしくは短縮識別子をプリフィックスとして、他モジュールからexportされた識別子を利用する。たとえば、上記のようにimportを行ったとき、以下のように識別子をアクセスできる。

  1. モジュール名A.識別子
  2. モジュール階層.モジュール階層.モジュール名B.識別子
  3. 短縮識別子C.識別子
  4. 短縮識別子D.識別子

3,4の「短縮識別子」はこの記事を書く際に便宜上付けた名前であり正式名称は不明。 短縮識別子は短かい必要はないが1文字が多く使われる(Signal→Sなど)。4.のように階層のある名前例えば「Graphics.Element.Field」に「Field」という短縮識別子を付けるなどもできる。

短縮識別子は同じものを複数回指定できないので、Qualified Importでは識別子の衝突が発生しない。(モジュール名があらかじめ衝突していない前提であるが。)

中置演算子のインポートは、Qualified Importではできない。後述のOpen Importを使用する必要がある。

例1:

import Text

main=Text.plainText "abc"

例2:

import Text
import Graphics.Element

main=Graphics.Element.flow Graphics.Element.right [ Text.asText "ABC" ]

例3:

import Text as T
import Graphics.Element as Element

main=Element.flow Element.right [ T.asText "ABC" ]

例4

import Text(asText)
import Signal as S -- 短縮識別子S
import List as L -- 短縮識別子L
import Signal(..)

main =  S.map asText <| constant ( L.map (\x -> x+1)   [1,2,3]  )

Open Import

一般形式:

  1. import モジュール名A(..)
  2. import モジュール階層.モジュール階層.モジュール名B(..)
  3. import モジュール名C(識別子,識別子,識別子…)
  4. import モジュール階層.モジュール階層.モジュール名D(識別子,識別子,識別子…)

説明:

Open Importは、指定したモジュールで定義・エクスポートされた識別子をすべて(1,2のケース)あるいは列挙したもの(3,4のケース)を、importする側の名前空間に取り込んで、前置指定も無く利用できるようにする。識別子の衝突が発生する可能性があり、その可能性は、1,2>3.4である。

例5

import Text(..)

main=plainText "abc"

例6

import Text(..)
import Graphics.Element(..)

main=flow right [ asText "ABC" ]

例7

import Text(asText)
import List((::)) -- 中置演算子::のOpen Import
import Signal
import Signal(constant) -- Qualified ImportとOpen Importを組合わせる

main=(Signal.map) asText (constant (2::[3,4,5]))

型のOpen Importについて

判別共用体型(Tagged Union, ADT)は、「型コンストラクタだけをimportして値コンストラクタをインポートしない」「指定した値コンストラクタだけをインポートする」などが可能である。

Qualified ImportとOpen Importの使い分け

簡潔さの程度でいうと以下の順である(上の方ほど字数が少ない)。

  1. 識別子を指定せずにOpen Import
  2. 識別子を指定してOpen Inport
  3. Qualified importで短縮識別子使用
  4. Qualified importで短縮識別子使用しない

mapなどいかにも重なりそうな名前があるので、書き捨てコード以外は3か4、最悪でも2を選んでおくのが安全ではあるが、衝突は滅多に無い気もするな…はて。出現頻度が高いものは簡潔に書きたいので、importするモジュールごとに、そして書く内容によってそれぞれ判断したい気もする。elm-htmlとか既存のコードでどうやってるかを参考にするのも良いのではないかと。

デフォルトのimport

任意のElmプログラムで、以下が指定されているのと同じ動作をする。 (参考の下の方 )

  • import Basics (..)
  • import List ( List )
  • import Maybe ( Maybe( Just, Nothing ) )
  • import Result ( Result( Ok, Err ) )
  • import Signal ( Signal )

Listの::や、Signalの<~, ~が(Elm 0.14では少なくとも)デフォルトインポートされていないことに注意。前はElementとかSignal(..)などもデフォルトインポートされてたんだけどな…(´・ω・`)。

おまけ:

割と最近出た書籍「Seven More Languages in Seven Weeks: Languages That Are Shaping the Future」にはElmの章があるようです。ぽちっとな。

Seven More Languages in Seven Weeks: Languages That Are Shaping the Future
Bruce A. Tate Frederic Daoud Ian Dees Jack Moffitt
Pragmatic Bookshelf
売り上げランキング: 9,168

関連リンク

「Elmでやってみる」シリーズのまとめエントリ - uehaj's blog