回答:
私はそれをどう思いますか:
type
新しいユニオンタイプを定義するために使用されます。
type Thing = Something | SomethingElse
この定義の前にSomething
してSomethingElse
何の意味もありませんでした。これらはどちらもタイプでThing
、先ほど定義したとおりです。
type alias
すでに存在する他のタイプに名前を付けるために使用されます:
type alias Location = { lat:Int, long:Int }
{ lat = 5, long = 10 }
タイプ{ lat:Int, long:Int }
はすでに有効なタイプです。しかしLocation
、同じ型のエイリアスであるため、型があるとも言えます。
次のコードは問題なくコンパイルされて表示されることに注意してください"thing"
。thing
is を指定してString
をaliasedStringIdentity
受け取りますが、/のAliasedString
間に型の不一致があるというエラーは発生しません。String
AliasedString
import Graphics.Element exposing (show)
type alias AliasedString = String
aliasedStringIdentity: AliasedString -> AliasedString
aliasedStringIdentity s = s
thing : String
thing = "thing"
main =
show <| aliasedStringIdentity thing
{ lat:Int, long:Int }
新しいタイプを定義しません。これはすでに有効なタイプです。type alias Location = { lat:Int, long:Int }
また、新しいタイプを定義せず、すでに有効なタイプに別の(おそらくより説明的な)名前を付けます。type Location = Geo { lat:Int, long:Int }
新しいタイプ(Location
)を定義します
キーは言葉alias
です。プログラミングの過程で、属しているものをグループ化したい場合は、ポイントの場合のように、それをレコードに入れます
{ x = 5, y = 4 }
または学生の記録。
{ name = "Billy Bob", grade = 10, classof = 1998 }
これらのレコードを渡す必要がある場合は、次のようにタイプ全体を綴る必要があります。
add : { x:Int, y:Int } -> { x:Int, y:Int } -> { x:Int, y:Int }
add a b =
{ a.x + b.x, a.y + b.y }
ポイントにエイリアスを付けることができれば、署名は非常に簡単に記述できます!
type alias Point = { x:Int, y:Int }
add : Point -> Point -> Point
add a b =
{ a.x + b.x, a.y + b.y }
したがって、エイリアスは他のものの省略形です。ここでは、レコードタイプの省略形です。頻繁に使用するレコードタイプに名前を付けると考えることができます。これがエイリアスと呼ばれる理由です。これは、次の式で表されるネイキッドレコードタイプの別名です{ x:Int, y:Int }
一方type
、別の問題を解決します。OOPを使用している場合は、継承や演算子のオーバーロードなどで解決する問題です。データを一般的なものとして扱いたい場合もあれば、特定のもののように扱いたい場合もあります。
これが発生する一般的な場所は、郵便システムのようにメッセージを渡すときです。手紙を送るとき、郵便システムがすべてのメッセージを同じものとして扱うようにしたいので、郵便システムを設計する必要があるのは一度だけです。さらに、メッセージをルーティングするジョブは、その中に含まれるメッセージとは独立している必要があります。手紙が目的地に到着したときにのみ、メッセージが何であるかを気にします。
同様に、発生する可能性のtype
あるすべてのタイプのメッセージの結合としてを定義する場合があります。大学生とその親の間でメッセージングシステムを実装しているとします。したがって、大学生が送信できるメッセージは、「ビールのお金が必要」と「パンツが必要」の2つだけです。
type MessageHome = NeedBeerMoney | NeedUnderpants
したがって、ルーティングシステムを設計するとき、関数のMessageHome
タイプは、メッセージのすべての異なるタイプについて心配するのではなく、単に渡すことができます。ルーティングシステムは関係ありません。それがであることを知る必要があるだけMessageHome
です。それが何であるかを理解する必要があるのは、メッセージがその宛先である親の家に到達したときだけです。
case message of
NeedBeerMoney ->
sayNo()
NeedUnderpants ->
sendUnderpants(3)
Elmアーキテクチャを知っている場合、更新関数は巨大なcaseステートメントです。これは、メッセージがルーティングされて処理される宛先であるためです。また、ユニオンタイプを使用して、メッセージを渡すときに処理する単一のタイプを使用しますが、Caseステートメントを使用して、メッセージを正確に切り出し、処理できます。
ユースケースに焦点を当て、コンストラクター関数とモジュールに関する簡単なコンテキストを提供することで、以前の回答を補足しましょう。
type alias
レコードのエイリアスとコンストラクター関数を作成する
これが最も一般的なユースケースです。特定の種類のレコード形式に対して代替名とコンストラクター関数を定義できます。
type alias Person =
{ name : String
, age : Int
}
タイプエイリアスを定義すると、次のコンストラクタ関数(疑似コード)が自動的
Person : String -> Int -> { name : String, age : Int }
に含まれます。これは、たとえばJsonデコーダを作成する場合などに便利です。
personDecoder : Json.Decode.Decoder Person
personDecoder =
Json.Decode.map2 Person
(Json.Decode.field "name" Json.Decode.String)
(Json.Decode.field "age" Int)
必須フィールド
を指定する彼らは時々それを「拡張可能レコード」と呼び、誤解を招く可能性があります。この構文を使用して、特定のフィールドが存在するレコードを予期していることを指定できます。といった:
type alias NamedThing x =
{ x
| name : String
}
showName : NamedThing x -> Html msg
showName thing =
Html.text thing.name
次に、上記の関数を次のように使用できます(たとえば、ビューで)。
let
joe = { name = "Joe", age = 34 }
in
showName joe
ElmEurope 2017に関するRichard Feldmanの講演は、このスタイルがいつ使用する価値があるかについてのさらなる洞察を提供するかもしれません。
ものの名前の変更
、新しい名前は、この例のように、後であなたのコード内の余分な意味を提供することができますので、あなたがこれを行う可能性がありますが
type alias Id = String
type alias ElapsedTime = Time
type SessionStatus
= NotStarted
| Active Id ElapsedTime
| Finished Id
別のモジュールから型を再公開する
(アプリケーションではなく)パッケージを作成している場合、1つのモジュール、おそらく内部(非公開)モジュールに型を実装する必要があるかもしれませんが、別の(パブリック)モジュール。または、代わりに、複数のモジュールから型を公開する必要があります。最初の例
Task
はコアのHttp.Requestで、後者の例はJson.Encode.ValueとJson.Decode.Valueのペアです。
型を不透明にしたい場合にのみ、これを行うことができます。コンストラクター関数を公開しないでください。詳細については、type
以下の使用法を参照してください。
上記の例では#1のみがコンストラクター関数を提供していることに注意してください。#1でタイプエイリアスmodule Data exposing (Person)
を公開すると、タイプ名とコンストラクター関数が公開されます。
type
タグ付き共用体タイプを定義する
これは最も一般的なユースケースでありMaybe
、コアのタイプがその良い例です。
type Maybe a
= Just a
| Nothing
タイプを定義するときは、そのコンストラクター関数も定義します。多分これらは(疑似コード)です:
Just : a -> Maybe a
Nothing : Maybe a
つまり、この値を宣言すると、
mayHaveANumber : Maybe Int
どちらでも作成できます
mayHaveANumber = Nothing
または
mayHaveANumber = Just 5
タグだけでなく、彼らはまた、デストラクタやパターンとして機能し、コンストラクター関数として機能表現。つまり、これらのパターンを使用すると、内部で確認できます。Just
Nothing
case
Maybe
showValue : Maybe Int -> Html msg
showValue mayHaveANumber =
case mayHaveANumber of
Nothing ->
Html.text "N/A"
Just number ->
Html.text (toString number)
Maybeモジュールは次のように定義されているので、これを行うことができます
module Maybe exposing
( Maybe(Just,Nothing)
それはまた言うことができます
module Maybe exposing
( Maybe(..)
この場合、2つは同等ですが、特にパッケージを作成している場合、Elmでは明示的であることは美徳と見なされます。
実装の詳細を非表示に
する上記で指摘したように、コンストラクター関数がMaybe
他のモジュールから見えるようにするのは意図的な選択です。
ただし、作成者が非表示にすることを決定する場合もあります。コアでのこの1つの例はDict
です。パッケージのコンシューマーとして、背後にあるRed / Blackツリーアルゴリズムの実装の詳細を確認しDict
たり、ノードを直接操作したりすることはできません。コンストラクター関数を非表示にすると、モジュール/パッケージのコンシューマーは、公開する関数を介して型の値のみを作成(そしてそれらの値を変換)します。
これが時々このようなものがコードに現れる理由です
type Person =
Person { name : String, age : Int }
type alias
この投稿の冒頭の定義とは異なり、この構文はコンストラクター関数を1つだけ持つ新しい「共用体」型を作成しますが、そのコンストラクター関数は他のモジュール/パッケージから隠すことができます。
タイプが次のように公開されている場合:
module Data exposing (Person)
Data
モジュール内のコードのみがPerson値を作成でき、そのコードのみがそれにパターンマッチできます。
私が見るように、主な違いは、「類義的な」タイプを使用した場合にタイプチェッカーがあなたに怒鳴るかどうかです。
次のファイルを作成し、どこかに配置して実行しelm-reactor
、次に移動しhttp://localhost:8000
て違いを確認します。
-- Boilerplate code
module Main exposing (main)
import Html exposing (..)
main =
Html.beginnerProgram
{
model = identity,
view = view,
update = identity
}
-- Our type system
type alias IntRecordAlias = {x : Int}
type IntRecordType =
IntRecordType {x : Int}
inc : {x : Int} -> {x : Int}
inc r = {r | x = .x r + 1}
view model =
let
-- 1. This will work
r : IntRecordAlias
r = {x = 1}
-- 2. However, this won't work
-- r : IntRecordType
-- r = IntRecordType {x = 1}
in
Html.text <| toString <| inc r
2.
コメントを外してコメント1.
すると、次のように表示されます。
The argument to function `inc` is causing a mismatch.
34| inc r
^
Function `inc` is expecting the argument to be:
{ x : Int }
But it is:
IntRecordType
アンは、alias
類似した他のいくつかのタイプ、のためだけの短い名前ですclass
OOPインチ 経験:
type alias Point =
{ x : Int
, y : Int
}
type
あなたのようなタイプを定義することができるように(別名なし)は、独自の型を定義できるようになるInt
、String
アプリ、...あなたのために。たとえば、一般的なケースでは、アプリの状態の説明に使用できます。
type AppState =
Loading --loading state
|Loaded --load successful
|Error String --Loading error
したがって、view
elmで簡単に処理できます。
-- VIEW
...
case appState of
Loading -> showSpinner
Loaded -> showSuccessData
Error error -> showError
...
私はあなたが違いを知っていると思うtype
と、をtype alias
。
しかし、なぜ、どのように使用しtype
、アプリでtype alias
重要なのか、Josh Claytonの記事をelm
参照してください。