PureScriptの全てのコードはモジュールに含まれます。モジュールはmodule
キーワードによって導入されます:
module A where
id x = x
モジュールはimport
キーワードを使うことで読み込まれます。これは「openインポート」と呼ばれ、モジュール内の全ての値や型の別名を作成します:
module B where
import A
代わりに、カッコ内に指定して読み込むことも可能です:
module B where
import A (runFoo)
値、演算子(丸括弧で囲んでおく)、型コンストラクタ、データコンストラクタ、型クラスは全て明示的に読み込むことができます。型コンスタクタの後の丸括弧内に関連するデータコンストラクタを書き連ねることもでき、ピリオドを2つ(..
)書くと、型コンストラクタの全てのデータコンストラクタがインポートされます。
module B where
import A (runFoo, (.~), Foo(..), Bar(Bar))
型クラスをインポートするにはclass
キーワードを使います。種の場合はkind
です。
module B where
import A (class Fab, kind Effect)
hiding
キーワードを使って、openインポートから除外する名前を指定できます。これはモジュール間でインポートした名前が衝突することを防ぐときに便利です。
module C where
import A hiding (runFoo)
import B (runFoo)
修飾インポート
モジュールは修飾名付きでインポートすることもできます。つまり、モジュールの名前はそのままスコープに入れられるのではなく、別名として入れられます。
以下は修飾インポートが非常に便利に使える場面です。
import Data.Map as Map
a :: Map Int String
a = Map.fromFoldable [ Tuple 1 "a" ]
いくつかのデータ構造モジュールは、別のFoldable
データ構造からそのデータ構造のインスタンスを作成できるfromFoldable
関数を持っています。どのfromFoldable
関数が使われているのかを明確にするために、Set.fromFoldable
のようにインポートの際に付けた修飾名のあとに関数名を書くことができます。
別の例として、ここでは架空のモジュールを使います:
import MyWebFramework as MyWebFramework
main :: Eff (dom :: DOM) Unit
main = do
elem <- domElementById "appContainer"
MyWebFramework.run elem
-- ^ this may be more clear than
-- `run elem`
"run"はどこにでもありそうな名前なので、読む前にその関数の型を知らなければ、そのモジュールがMyWebFramework
であると知るまではrun
関数が何をするためのものなのかが不明確です。次の人がこのコードを読んだときの混乱を軽減するために、MyWebFramework.run
のように修飾付きでインポートして使用することができます。
module Main where
import Data.Array as Array
null = ...
test = Array.null [1, 2, 3]
ここで、名前null
はData.Array
のnull
と衝突していましたが、修飾インポートがこれを解決します。Array.null
を使ってData.Array.null
を参照することができます。
演算子も同じようにして参照することが可能です:
test' = Array.null ([1, 2, 3] Array.\\ [1, 2, 3])
修飾インポートで同じ名前を用いることでモジュール同士を統合することができます。複数のモジュールをマージするときは、衝突を避けるために明示インポートの使用を考えてください:
module Main where
import Data.String.Regex (split) as Re
import Data.String.Regex.Flags (global) as Re
import Data.String.Regex.Unsafe (unsafeRegex) as Re
split = Re.split (Re.unsafeRegex "[,;:.]\\s+" Re.global)
そのモジュールから何を公開するのかについて、公開リストを使用して制御できます。公開リストが使用された時、外部から見えるのは公開リストに含まれたもののみになります。例えば:
module A (exported) where
exported :: Int -> Int
exported = [...]
notExported :: Int -> Int
notExported = [...]
この場合、モジュールA
をインポートしてもnotExported
関数は見えません。
公開できる名前の種類はモジュールのインポートの場合と同じです。
インポートされたモジュールは全体を再公開することができます:
module A (module B) where
import B
修飾・明示インポートも可能です:
module A (module MoreExports) where
import A.Util (useful, usefulFn) as MoreExports
import A.Type (ADatatype(..)) as MoreExports
他のモジュールを再公開している時、自モジュールも公開リストに含めることで、全ての値や型も公開することができます:
module A (module A, module B) where
import B
data ...
型クラスを公開するためには、単に型クラスとそのメンバをリストに含めます。残念ながら、型クラスのメンバ全てを一度に公開するようなショートハンドはありません。
例として、以下を考えます:
class Foldable f where
foldr :: forall a b. (a -> b -> b) -> b -> (f a) -> b
foldl :: forall a b. (b -> a -> b) -> b -> (f a) -> b
foldMap :: forall a m. (Monoid m) => (a -> m) -> (f a) -> m
このとき、以下のようにして型クラスを公開します:
module Test (class Foldable, foldr, foldl, foldMap) where
型クラスが公開される時には、その全てのメンバも公開されなければなりません。同様に、型クラスのメンバが公開されるときには、それが属する型クラスも公開されなければなりません。