유형 및 유형 별칭 간의 Elm의 차이점은 무엇입니까?
Elm에서는 type
적절한 키워드와 type alias
. 문서에 이에 대한 설명이없는 것 같으며 릴리스 정보에서도 찾을 수 없습니다. 어딘가에 문서화되어 있습니까?
내가 생각하는 방법 :
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
인 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
핵심은 단어 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
모든 다른 유형의 메시지의 결합으로 정의 할 수 있습니다 . 대학생과 부모 사이에 메시징 시스템을 구현한다고 가정 해 보겠습니다. 그래서 대학생들이 보낼 수있는 메시지는 '맥주 돈이 필요해'와 '속옷이 필요해'두 가지뿐입니다.
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
Richard Feldman's talk on ElmEurope 2017 may provide some further insight into when this style is worth using.
Renaming stuff
You might do this, because the new names could provide extra meaning later on in your code, like in this exampletype alias Id = String type alias ElapsedTime = Time type SessionStatus = NotStarted | Active Id ElapsedTime | Finished Id
Perhaps a better example of this kind of usage in core is
Time
.
Re-exposing a type from a different module
If you are writing a package (not an application), you may need to implement a type in one module, perhaps in an internal (not exposed) module, but you want to expose the type from a different (public) module. Or, alternatively, you want to expose your type from multiple modules.
Task
in core and Http.Request in Http are examples for the first, while the Json.Encode.Value and Json.Decode.Value pair is an example of the later.You can only do this when you otherwise want to keep the type opaque: you don't expose the constructor functions. For details see usages of
type
below.
It is worth noticing that in the above examples only #1 provides a constructor function. If you expose your type alias in #1 like module Data exposing (Person)
that will expose the type name as well as the constructor function.
Usages of type
Define a tagged union type
This is the most common use-case, a good example of it is theMaybe
type in core:type Maybe a = Just a | Nothing
When you define a type, you also define its constructor functions. In case of Maybe these are (pseudo-code):
Just : a -> Maybe a Nothing : Maybe a
Which means that if you declare this value:
mayHaveANumber : Maybe Int
You can create it by either
mayHaveANumber = Nothing
or
mayHaveANumber = Just 5
The
Just
andNothing
tags not only serve as constructor functions, they also serve as destructors or patterns in acase
expression. Which means that using these patterns you can see inside aMaybe
:showValue : Maybe Int -> Html msg showValue mayHaveANumber = case mayHaveANumber of Nothing -> Html.text "N/A" Just number -> Html.text (toString number)
You can do this, because the Maybe module is defined like
module Maybe exposing ( Maybe(Just,Nothing)
It could also say
module Maybe exposing ( Maybe(..)
The two are equivalent in this case, but being explicit is considered a virtue in Elm, especially when you are writing a package.
Hiding implementation details
As pointed out above it is a deliberate choice that the constructor functions ofMaybe
are visible for other modules.There are other cases, however, when the author decides to hide them. One example of this in core is
Dict
. As the consumer of the package, you should not be able to see the implementation details of the Red/Black tree algorithm behindDict
and mess with the nodes directly. Hiding the constructor functions forces the consumer of your module/package to only create values of your type (and then transform those values) through the functions you expose.This is the reason why sometimes stuff like this appears in code
type Person = Person { name : String, age : Int }
Unlike the
type alias
definition at the top of this post, this syntax creates a new "union" type with only one constructor function, but that constructor function can be hidden from other modules/packages.If the type is exposed like this:
module Data exposing (Person)
Only code in the
Data
module can create a Person value and only that code can pattern match on it.
The main difference, as I see it, is whether type checker will yell on you if you use "synomical" type.
Create the following file, put it somewhere and run elm-reactor
, then go to http://localhost:8000
to see the difference:
-- 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
If you uncomment 2.
and comment 1.
you will see:
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
An alias
is just a shorter name for some other type, similar class
in OOP. Exp:
type alias Point =
{ x : Int
, y : Int
}
An type
(without alias) will let you define your own type, so you can define types like Int
, String
,... for you app. For exmaple, in common case, it can use for description of a state of app:
type AppState =
Loading --loading state
|Loaded --load successful
|Error String --Loading error
So you you can easy to handle it in view
elm:
-- VIEW
...
case appState of
Loading -> showSpinner
Loaded -> showSuccessData
Error error -> showError
...
I think you know the difference between type
and type alias
.
But why and how to use type
and type alias
is important with elm
app, you guys can refer the article from Josh Clayton
참고URL : https://stackoverflow.com/questions/32187565/difference-in-elm-between-type-and-type-alias
'Programing' 카테고리의 다른 글
Linux Bash에서 이중 앰퍼샌드 (&&)와 세미콜론 (;)의 차이점은 무엇입니까? (0) | 2020.09.05 |
---|---|
Node.js에서 콜백을 프라 미스로 대체 (0) | 2020.09.05 |
플렉스 박스 요소 중앙 및 오른쪽 정렬 (0) | 2020.09.05 |
하드 랩과 소프트 랩의 차이점은 무엇입니까? (0) | 2020.09.05 |
xUnit : 두 개의 목록을 지정 (0) | 2020.09.05 |