Zaman Elm, ben çözemiyorum type
uygun anahtar kelime vs olduğunu type alias
. Belgelerin bununla ilgili bir açıklaması yok gibi görünüyor, ne de sürüm notlarında bir açıklama bulamıyorum. Bu bir yerde belgelendi mi?
Yanıtlar:
Nasıl düşünüyorum:
type
yeni birleşim türlerini tanımlamak için kullanılır:
type Thing = Something | SomethingElse
Bu tanımdan önce Something
ve SomethingElse
hiçbir şey ifade etmiyordu. Şimdi her ikisi de, Thing
az önce tanımladığımız türden .
type alias
zaten var olan başka bir türe isim vermek için kullanılır:
type alias Location = { lat:Int, long:Int }
{ lat = 5, long = 10 }
türü olan { lat:Int, long:Int }
zaten geçerli bir tür oldu. Ama şimdi Location
, aynı tür için bir takma ad olduğu için , türüne sahip olduğunu da söyleyebiliriz .
Aşağıdakilerin iyi bir şekilde derleneceğini ve görüntüleneceğini belirtmekte fayda var "thing"
. Hatta, belirttiğimiz olsa thing
bir olduğunu String
ve aliasedStringIdentity
bir sürer AliasedString
, biz arasında bir tür uyuşmazlığı olduğunu bir hata almazsınız 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 }
yeni bir tür tanımlamaz. Bu zaten geçerli bir tür. type alias Location = { lat:Int, long:Int }
ayrıca yeni bir tür tanımlamaz, yalnızca zaten geçerli bir türe başka (belki daha açıklayıcı) bir ad verir. type Location = Geo { lat:Int, long:Int }
yeni bir tür tanımlar ( Location
)
Anahtar kelime alias
. Programlama sırasında, birbirine ait olan şeyleri gruplamak istediğinizde, bir noktada olduğu gibi bir kayda koyarsınız.
{ x = 5, y = 4 }
veya bir öğrenci kaydı.
{ name = "Billy Bob", grade = 10, classof = 1998 }
Şimdi, bu kayıtları başkasına iletmeniz gerekirse, tüm türü yazmanız gerekir, örneğin:
add : { x:Int, y:Int } -> { x:Int, y:Int } -> { x:Int, y:Int }
add a b =
{ a.x + b.x, a.y + b.y }
Bir noktayı değiştirebilseydiniz, imzayı yazmak çok daha kolay olurdu!
type alias Point = { x:Int, y:Int }
add : Point -> Point -> Point
add a b =
{ a.x + b.x, a.y + b.y }
Yani takma ad, başka bir şeyin kısaltmasıdır. Burada, bir kayıt türü için bir kısaltmadır. Bunu, sık kullanacağınız bir kayıt türüne bir isim vermek olarak düşünebilirsiniz. Bu yüzden takma ad olarak adlandırılır - temsil edilen çıplak kayıt türü için başka bir addır.{ x:Int, y:Int }
Oysa type
farklı bir sorunu çözer. OOP'den geliyorsanız, kalıtım, operatör aşırı yükleme vb. İle çözdüğünüz problemdir. - bazen veriyi genel bir şey olarak ele almak istersiniz ve bazen ona belirli bir şey gibi davranmak istersiniz.
Bunun olağan bir durumu, posta sistemi gibi mesajların etrafından dolaşılmasıdır. Bir mektup gönderdiğinizde, posta sisteminin tüm mesajları aynı şey olarak ele almasını istersiniz, böylece posta sistemini yalnızca bir kez tasarlamanız gerekir. Ayrıca, mesajı yönlendirme işi, içerdiği mesajdan bağımsız olmalıdır. Sadece mektup hedefine ulaştığında mesajın ne olduğunu umursuyorsunuz.
Aynı şekilde, bir olabilecek type
tüm farklı mesaj türlerinin bir birleşimi olarak tanımlayabiliriz . Üniversite öğrencileriyle ebeveynleri arasında bir mesajlaşma sistemi uyguladığımızı varsayalım. Yani üniversite öğrencilerinin gönderebileceği sadece iki mesaj var: 'Bira parasına ihtiyacım var' ve 'külota ihtiyacım var'.
type MessageHome = NeedBeerMoney | NeedUnderpants
Şimdi, yönlendirme sistemini tasarladığımızda, işlevlerimizin MessageHome
türleri, olabilecek tüm farklı mesaj türleri hakkında endişelenmek yerine , sadece dolaşabilir. Yönlendirme sistemi umursamıyor. Yalnızca bunun bir MessageHome
. Sadece mesaj hedefine, ebeveynin evine ulaştığında ne olduğunu anlamanız gerekir.
case message of
NeedBeerMoney ->
sayNo()
NeedUnderpants ->
sendUnderpants(3)
Elm mimarisini biliyorsanız, güncelleme işlevi dev bir durum ifadesidir, çünkü mesajın yönlendirildiği ve dolayısıyla işlendiği yer burasıdır. Ve mesajı iletirken tek bir türe sahip olmak için birleşim türlerini kullanıyoruz, ancak daha sonra tam olarak hangi mesaj olduğunu anlamak için bir case ifadesi kullanabiliriz, böylece onunla başa çıkabiliriz.
Kullanım durumlarına odaklanarak ve yapıcı işlevleri ve modülleri hakkında biraz bağlam sağlayarak önceki yanıtları tamamlayayım.
type alias
Bir kayıt için takma ad ve yapıcı işlevi oluşturma
Bu en yaygın kullanım durumu: belirli bir kayıt biçimi türü için alternatif bir ad ve yapıcı işlevi tanımlayabilirsiniz.
type alias Person =
{ name : String
, age : Int
}
Tür takma adını tanımlamak, otomatik olarak aşağıdaki yapıcı işlevini (sözde kod) ifade eder:
Person : String -> Int -> { name : String, age : Int }
Bu, örneğin bir Json kod çözücü yazmak istediğinizde kullanışlı olabilir.
personDecoder : Json.Decode.Decoder Person
personDecoder =
Json.Decode.map2 Person
(Json.Decode.field "name" Json.Decode.String)
(Json.Decode.field "age" Int)
Gerekli alanları belirtin
Bazen yanıltıcı olabilecek "genişletilebilir kayıtlar" olarak adlandırılırlar. Bu sözdizimi, belirli alanların mevcut olduğu bazı kayıtlar beklediğinizi belirtmek için kullanılabilir. Gibi:
type alias NamedThing x =
{ x
| name : String
}
showName : NamedThing x -> Html msg
showName thing =
Html.text thing.name
Ardından yukarıdaki işlevi şu şekilde kullanabilirsiniz (örneğin sizin görüşünüzde):
let
joe = { name = "Joe", age = 34 }
in
showName joe
Richard Feldman'ın ElmEurope 2017 hakkındaki konuşması, bu tarzın ne zaman kullanılmaya değer olduğuna dair daha fazla fikir verebilir.
Öğeleri yeniden adlandırma
Bunu yapabilirsiniz, çünkü bu örnekte olduğu gibi, yeni adlar daha sonra kodunuzda ekstra anlamlar sağlayabilir.
type alias Id = String
type alias ElapsedTime = Time
type SessionStatus
= NotStarted
| Active Id ElapsedTime
| Finished Id
Çekirdekte bu tür kullanımınTime
belki de daha iyi bir örneği .
Farklı bir modülden bir türü yeniden açığa çıkarma Bir
paket yazıyorsanız (bir uygulama değil), bir modülde, belki de dahili (açıkta olmayan) bir modülde bir tür uygulamanız gerekebilir, ancak türü farklı bir (genel) modül. Veya alternatif olarak, türünüzü birden çok modülden ortaya çıkarmak istiyorsunuz.
Task
in core ve Http içindeki Http.Request ilk örneklerdir, Json.Encode.Value ve Json.Decode.Value çifti ise daha sonraki bir örnektir.
Bunu yalnızca türü opak tutmak istediğinizde yapabilirsiniz: yapıcı işlevlerini açığa çıkarmazsınız. Ayrıntılar için type
aşağıdaki kullanımlara bakın.
Yukarıdaki örneklerde sadece # 1'in bir yapıcı işlevi sağladığına dikkat etmek önemlidir. Tür takma adınızı # 1'de böyle module Data exposing (Person)
gösterirseniz, yapıcı işlevinin yanı sıra tür adını da ortaya çıkarır.
type
Etiketli bir birleşim türü tanımlayın
Bu en yaygın kullanım durumudur, buna iyi bir örnek, Maybe
çekirdekteki türdür :
type Maybe a
= Just a
| Nothing
Bir tür tanımladığınızda, onun yapıcı işlevlerini de tanımlarsınız. Belki durumunda bunlar (sözde kod):
Just : a -> Maybe a
Nothing : Maybe a
Bu, bu değeri beyan ederseniz:
mayHaveANumber : Maybe Int
Şununla oluşturabilirsiniz:
mayHaveANumber = Nothing
veya
mayHaveANumber = Just 5
Just
Ve Nothing
etiketler sadece onlar da bir de yıkıcılar veya desen olarak hizmet, yapıcı işlevleri olarak hizmet case
ifadesi. Bu, bu kalıpları kullanarak aşağıdakileri görebileceğiniz anlamına gelir Maybe
:
showValue : Maybe Int -> Html msg
showValue mayHaveANumber =
case mayHaveANumber of
Nothing ->
Html.text "N/A"
Just number ->
Html.text (toString number)
Bunu yapabilirsiniz, çünkü Belki modülü şöyle tanımlanır:
module Maybe exposing
( Maybe(Just,Nothing)
Ayrıca diyebilirdi
module Maybe exposing
( Maybe(..)
Bu durumda ikisi eşdeğerdir, ancak özellikle bir paket yazarken Elm'de açık olmak bir erdem olarak kabul edilir.
Uygulama ayrıntılarını gizlemek
Yukarıda belirtildiği gibi, yapıcı işlevlerinin Maybe
diğer modüller için görünür olması bilinçli bir seçimdir .
Bununla birlikte, yazarın bunları gizlemeye karar verdiği başka durumlar da vardır. Çekirdekte bunun bir örneğiDict
. Paketin tüketicisi olarak, arkadaki Kırmızı / Siyah ağaç algoritmasının uygulama detaylarını görememeli Dict
ve düğümlerle doğrudan uğraşmamalısınız. Yapıcı işlevlerini gizlemek, modülünüzün / paketinizin tüketicisini yalnızca sizin türünüzdeki değerleri yaratmaya (ve sonra bu değerleri, sunduğunuz işlevler aracılığıyla dönüştürmeye) zorlar.
Bazen bunun gibi şeylerin kodda görünmesinin nedeni budur
type Person =
Person { name : String, age : Int }
Bu yazının üstündeki type alias
tanımdan farklı olarak , bu sözdizimi yalnızca bir yapıcı işlevle yeni bir "birleşim" türü oluşturur, ancak bu yapıcı işlevi diğer modüllerden / paketlerden gizlenebilir.
Tür bu şekilde ortaya çıkarsa:
module Data exposing (Person)
Yalnızca Data
modüldeki kod bir Kişi değeri oluşturabilir ve yalnızca bu kod bunun üzerinde kalıp eşleşebilir.
Gördüğüm kadarıyla temel fark, "eşzamanlı" tip kullanırsanız tip denetleyicisinin size bağırıp çağırmayacağıdır.
Aşağıdaki dosyayı oluşturun, bir yere koyun ve çalıştırın elm-reactor
, ardından http://localhost:8000
farkı görmek için gidin :
-- 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
Yorum yapmaz 2.
ve yorum 1.
yaparsanız şunu göreceksiniz:
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
, class
OOP'de benzer şekilde başka bir tür için sadece daha kısa bir isimdir . Tecrübe:
type alias Point =
{ x : Int
, y : Int
}
Bir type
sen gibi türlerini tanımlamak böylece (takma ad olmadan), kendi türünü tanımlamak izin verir Int
, String
uygulama, ... senin için. Örneğin, yaygın durumda, bir uygulama durumunun açıklaması için kullanılabilir:
type AppState =
Loading --loading state
|Loaded --load successful
|Error String --Loading error
Böylece view
karaağaçla kolayca başa çıkabilirsiniz :
-- VIEW
...
case appState of
Loading -> showSpinner
Loaded -> showSuccessData
Error error -> showError
...
Sanırım type
ve arasındaki farkı biliyorsunuz type alias
.
Ancak uygulama için neden ve nasıl kullanılacağı type
ve type alias
önemli olduğu elm
için , Josh Clayton'ın makalesine bakabilirsiniz.