Elmの型は、等価演算子(==)を使うと「同じかどうか」を調べられます。
非等価演算子は(/=)です(多くの言語の!=とは違います)。
等価演算子は、リテラル、タプル、レコード、カスタム型に対して使えます。
1 == 2
--> False
1 /= 2
--> True
(1, 2) == (2, 1)
--> False
type alias MyRecord = { myInt : Int, myStrings : List String }
a : MyRecord
a = MyRecord (1 + 1) ["hello world"]
type alias MyOtherRecord = { myInt : Int, myStrings : List String }
myStrings = (String.join " " ["hello", "world"]) :: []
b : MyOtherRecord
b = { myInt = 2, myStrings = myStrings}
a == b
--> True
なお、関数を比較すると実行時にプログラムがクラッシュします。関数の比較は決してしないでください。
比較演算子(<)、(<=)、(>)、(>=)と、関数min、max、compareは、comparable型に対して使えます。
comparable型は、比較できる組み込み型をすべてまとめた特別な型です。数値、文字、文字列、comparableな値の配列、comparableな値のタプルが含まれます。
1 < 1 + 1
--> True
'x' < 'X'
--> False
"abc" < "abz"
--> True
"abc" < "abcd"
--> True
"abc" < "b"
--> True
min [1 , 2, 9000] [10]
--> [1 , 2, 9000]
min (1, "hello") (3, "bye")
--> (1, "hello")
レコードやカスタム型など、それ以外の型の値は直接比較できません。
SetやDictのキーなど、一部の組み込み型では、内容がcomparableである必要があります。これらの構造は内部的な順序に依存しているためです。
comparableな値の配列はList.sortで並べ替えられ、comparableな値に変換できる値の配列はList.sortByで並べ替えられます。
階層的な並べ替え(ある基準で並べ、同じなら別の基準で順序を決める)が必要な場合は、タプルや配列をList.sortByで使うこともできます。タプルと配列は辞書順に並べ替えられるためです。
List.sort ["hi", "hello", "bye", "goodbye"]
--> ["bye", "goodbye", "hello", "hi"]
List.sortBy String.length ["hi", "hello", "bye", "goodbye"]
--> ["hi", "bye", "hello", "goodbye"]
-- sort by length, then alphabetically
List.sortBy (\str -> (String.length str, str)) ["hi", "mum", "hello", "sis", "bye", "dad"]
--> ["hi", "bye", "dad", "mum", "sis", "hello"]
関数compareは2つのcomparableな値を受け取り、Orderを返します。
Orderは、ある値が別の値より大きい(GT)、等しい(EQ)、小さい(LT)かを、1回の操作で判定できる型です。
compare 1 2
--> LT
compare "" ""
--> EQ
compare [12] []
--> GT
比較関数は、任意の型に対して作ることができ、たとえばList.sortWithでの並べ替えに使えます。
type Color = Red | Green | Blue
compareColors : Color -> Color -> Order
compareColors a b =
case (a, b) of
(Red, Red) -> EQ
(Red, _) -> LT
(_, Red) -> GT
(Green, Green) -> EQ
(Green, _) -> LT
(_, Green) -> GT
(Blue, Blue) -> EQ
List.sortWith compareColors [Blue, Red, Green, Green, Blue]
--> [Red, Green, Green, Blue, Blue]
突然、懐かしさが込み上げてきて、昔のBlorkemon™️のカードを引っ張り出したくなりませんか。
Blorkemon™️カードは、昔ながらのとても楽しいカード交換ゲームです。
それぞれのCardにはBlorkemon™️のモンスターが描かれていて、攻撃のパワーレベルも書かれています。運が良ければ、そのカードはキラかもしれません。
Blorkemon™️のカードはどれも、隣にあるカードより強そうに見えますが、ちゃんと確かめたほうがよいでしょう。
isMorePowerful関数を実装しましょう。1つ目の引数のカードが、もう一方より厳密に強い場合にTrueを返し、それ以外の場合はFalseを返します。
newthree = Card "Newthree" 120 False
scientuna = Card "Scientuna" 6 True
isMorePowerful newthree scientuna
--> True
手札いっぱいにBlorkemon™️のカードがあれば、最強の攻撃を繰り出せるはずです。
maxPower関数を実装しましょう。これは2枚のカードのうち、高いほうのパワーレベルを返します。
maxPower newthree scientuna
--> 120
少なくとも1枚ずつは、それぞれのBlorkemon™️のカードを持っていたはずです。でも、最後に確認してからずいぶん経ちました。Pulpapediaの公式リストと比べるために、カードを並べ替えましょう。
sortByMonsterName関数を実装しましょう。これはCardsのリストを受け取り、モンスター名で並べ替えたリストを返します。
sortByMonsterName [newthree, scientuna]
--> [Card "Newthree" 120 False, Card "Scientuna" 6 True]
Blorkemon™️は、この世でいちばんかっこいい存在です。 これは軽々しく言っているのではありません。それを証明する科学的な方法があるのです。
sortByCoolness関数を実装しましょう。これはカードのリストを、いちばんかっこいいものを先頭にして並べ替えます。
カードのかっこよさは、まずキラかどうかで決まります。キラカードは、それ以外のカードよりずっとかっこいいのです。
次に基準になるのはパワーレベルで、高ければ高いほど良いです。
sortByCoolness [newthree, scientuna]
--> [Card "Scientuna" 6 True, Card "Newthree" 120 False]
キラは見た目だけのものではありません。同じパワーのBlorkemon™️同士の戦いでは、キラのほうが必ず勝ちます。 これはキラパワーと呼ばれています。
compareShinyPower関数を実装しましょう。この関数は、この性質をルールとして書き表します。
2枚のカードのOrderは、パワーレベルが異なればパワーレベルで決まりますが、等しい場合はキラのカードのほうが大きくなります。
compareShinyPower newthree scientuna
--> GT
Blorkemon™️カードのゲームでは何が起こるかわかりませんが、それでも強いカードほど勝ちやすい傾向があります。
expectedWinner関数を実装しましょう。これはcompareShinyPowerの順序に従って、勝つ見込みが最も高いモンスターの名前を返します。
この関数は、勝つと予想されるモンスターの名前を返します。両者のキラパワーが同じ場合は、"too close to call"を返します。
expectedWinner newthree scientuna
--> "Newthree"