関数のエクスポートは最初のコンセプトで扱いました。ここで簡単におさらいしておきましょう。
Elmの各ファイルはモジュールであり、他のどのコードよりも先にmodule文を書かなければなりません。
モジュール名はファイル名と一致していなければなりません。つまり、モジュールCalculatorはファイルCalculator.elmに、モジュールParser.UtilsはファイルParser/Utils.elmに置く必要があります。
モジュール内で定義したものは、exposingに挙げない限り、そのモジュールの中だけに閉じていて、外からアクセスすることはできません。
-- Calculator.elm
-- Define the Calculator module, and expose the `add` function
module Calculator exposing (add)
six = 3 + 3
add number1 number2 = number1 + number2
-- Calculator.elm
-- Define the Calculator module, and expose everything within: `six` and `add`
module Calculator exposing (..)
six = 3 + 3
add number1 number2 = number1 + number2
https://elm-lang.org/docs/syntax#modules
他のモジュールで定義された関数にアクセスするには、インポートを使います。 そのモジュールをインポートすると、そこで公開されている関数はすべてアクセスできるようになります。 ただし、アクセスのしかたはモジュールのインポートのしかたによって変わります。
デフォルトは修飾インポートで、このようにインポートしたモジュールの関数(たとえばListモジュールのmap関数)にアクセスするときは、モジュール名を前に付けます(List.map)。
オープンインポートを使うと、そのモジュールで公開されている関数に、接頭辞なしで直接アクセスできます。これはexposingキーワードで行い、エクスポートで使うものとちょうど対になります。利用できる関数をすべて公開することも(..)、特定の関数だけを公開することもできます(たとえばmap)。
他のモジュールから型やそのコンストラクターをインポートすることもできますが、これは後のコンセプトで扱います。
名前の衝突を避けて読みやすくするために、修飾インポートが好まれます。
-- qualified imports
import List -- List.map, List.foldl
import List as L -- L.map, L.foldl
-- open imports
import List exposing (..) -- map, foldl, concat, ...
import List exposing ( map, foldl ) -- map, foldl, List.concat
https://elm-lang.org/docs/syntax#modules
型注釈はname : parameter types -> return typeのように定義し、引数の型も->で区切ります。
add : Int -> Int -> Int
add number1 number2 = number1 + number2
関数の引数を定義するときは、括弧(())を使うこともできます(引数自身も同じ構文で定義するため、括弧が必要になるからです)。
-- Transform every character in a string
map : (Char -> Char) -> String -> String
map charMapperFunction string =
-- ...
https://elm-lang.org/docs/syntax#type-annotations
Elmで使える数値には2つの型があり、Int型とFloat型で定義されています。
Intは正と負の整数の集合に対応します。
Floatは実数の集合に対応し、コンピューターの精度によって制限されます。
数値に対して定義された演算は、ふつうどちらか一方の型でしか使えず、両者を混ぜることはできません。
2つの型の間で変換する関数も用意されています。たとえばtoFloatはIntをFloatに変換し、round、floor、ceiling、truncateはそれぞれ異なる意味でFloatをIntに変換します。
https://package.elm-lang.org/packages/elm/core/latest/Basics#Int
コードで単語や文を表すために、ElmにはネイティブのString型があります。
文字列リテラルは、"Hello World!"のように二重引用符で囲んで書きます。
文字列の連結演算子++と等価演算子==は標準で使えます。
hello : String -> String
hello subject = "Hello " ++ subject
hello "World!" --> "Hello World!"
その他の文字列関数のほとんどはStringモジュールにあり、インポートが必要です。
https://package.elm-lang.org/packages/elm/core/latest/String
この演習では、自転車と部品のオンラインショップ、Betty's Bike Shopを手伝うためのコードを書きます。 タスクは3つあり、いずれもウェブサイト上で自転車と部品の価格を正しく表示するためのものです。
penceToPounds関数をエクスポートする同僚はすでにモジュールの骨組み、つまり未定義のpenceToPounds関数とpoundsToString関数を書いています。
しかし、penceToPounds関数のエクスポートを忘れているため、現時点では他のモジュールからもテストスイートからも見えません。
エクスポートする関数のリストにpenceToPoundsを追加しましょう。
現在、価格は整数のペンスとして保存されています(この自転車店はイギリスにあります)。
ウェブサイトでは、価格をポンドで表示したいと考えています。1.00ポンドは100ペンスに相当します。
2つ目のタスクは、penceToPounds関数を実装することです。この関数はペンスの額をIntで受け取り、それに相当するポンドをFloatとして返します。
この関数の型注釈も定義しましょう。
penceToPounds 106
--> 1.06
Betty's Bike Shopの自転車はポンドで販売されているため、価格は"£"という記号を付けて表示します。
3つ目のタスクは、poundsToString関数を実装することです。この関数はポンドの額をFloatで受け取り、ポンド記号を先頭に付けた価格をStringとして返します。
Stringモジュールには、このために役立つString.fromFloat関数があります。
使用する前にStringモジュールをインポートしましょう。
poundsToStringの型注釈も定義しましょう。
poundsToString 1.06
--> "£1.06"