Skip to content

Latest commit

 

History

History
285 lines (217 loc) · 9.93 KB

Modules.md

File metadata and controls

285 lines (217 loc) · 9.93 KB

モジュール

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]

ここで、名前nullData.Arraynullと衝突していましたが、修飾インポートがこれを解決します。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

型クラスが公開される時には、その全てのメンバも公開されなければなりません。同様に、型クラスのメンバが公開されるときには、それが属する型クラスも公開されなければなりません。