प्रकार और उपनाम के बीच एल्म में अंतर?


93

एल्म में, मैं समझ नहीं सकता typeकि उपयुक्त कीवर्ड बनाम कब है type alias। दस्तावेज़ीकरण में इसकी व्याख्या नहीं है, और न ही मुझे जारी नोटों में कोई मिल सकता है। क्या यह कहीं दस्तावेज है?

जवाबों:


136

मैं इसे कैसे समझता हूं:

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

अंतिम पैराग्राफ की अपनी बात के बारे में निश्चित नहीं है। क्या आप कहने की कोशिश कर रहे हैं कि वे अभी भी उसी प्रकार के हैं, चाहे आप इसे कैसे लिखें?
झांग चेंग

7
हां, केवल यह इंगित करते हुए कि संकलक
अलियास

इसलिए जब आप {}रिकॉर्ड सिंटैक्स का उपयोग करते हैं , तो आप एक नए प्रकार को परिभाषित कर रहे हैं?

2
{ lat:Int, long:Int }एक नए प्रकार को परिभाषित नहीं करता है। यह पहले से ही मान्य प्रकार है। type alias Location = { lat:Int, long:Int }यह भी एक नए प्रकार को परिभाषित नहीं करता है, यह पहले से ही मान्य प्रकार को एक और (शायद अधिक वर्णनात्मक) नाम देता है। type Location = Geo { lat:Int, long:Int }एक नए प्रकार को परिभाषित करेगा ( Location)
robertjlooby

1
एक प्रकार बनाम उर्फ ​​का उपयोग कब करना चाहिए? हमेशा उपयोग करने वाले प्रकार का नकारात्मक पहलू कहां है?
रिचर्ड हेवेन

8

कुंजी शब्द है 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)

यदि आप एल्म आर्किटेक्चर को जानते हैं, तो अपडेट फ़ंक्शन एक विशाल केस स्टेटमेंट है, क्योंकि यह वह स्थान है जहां संदेश रूट हो जाता है, और इसलिए संसाधित किया जाता है। और हम मैसेज पास करते समय डील करने के लिए यूनियन टाइप का उपयोग करते हैं, लेकिन फिर केस स्टेटमेंट का उपयोग करके यह बता सकते हैं कि यह क्या संदेश था, इसलिए हम इससे निपट सकते हैं।


5

मुझे उपयोग-मामलों पर ध्यान केंद्रित करके और निर्माण कार्यों और मॉड्यूल पर थोड़ा संदर्भ प्रदान करके पिछले उत्तरों को पूरक करने दें।



के Usages type alias

  1. एक रिकॉर्ड के लिए एक उपनाम और एक निर्माता फ़ंक्शन बनाएं
    यह सबसे आम उपयोग-मामला है: आप एक विशेष प्रकार के रिकॉर्ड प्रारूप के लिए एक वैकल्पिक नाम और निर्माता फ़ंक्शन को परिभाषित कर सकते हैं।

    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)


  2. आवश्यक फ़ील्ड निर्दिष्ट करें
    वे कभी-कभी इसे "एक्स्टेंसिबल रिकॉर्ड" कहते हैं, जो भ्रामक हो सकता है। इस सिंटैक्स का उपयोग यह निर्दिष्ट करने के लिए किया जा सकता है कि आप विशेष क्षेत्र के साथ कुछ रिकॉर्ड की उम्मीद कर रहे हैं। जैसे कि:

    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 पर रिचर्ड फेल्डमैन की बात इस शैली का उपयोग करने के लिए कुछ और जानकारी प्रदान कर सकती है।

  3. सामान का नाम बदलना
    आप ऐसा कर सकते हैं, क्योंकि नए नाम आपके कोड में बाद में इस उदाहरण की तरह अतिरिक्त अर्थ प्रदान कर सकते हैं

    type alias Id = String
    
    type alias ElapsedTime = Time
    
    type SessionStatus
        = NotStarted
        | Active Id ElapsedTime
        | Finished Id

    कोर में इस तरह के उपयोगTime का शायद एक बेहतर उदाहरण है

  4. एक अलग मॉड्यूल से एक प्रकार को फिर से उजागर करना
    यदि आप एक पैकेज लिख रहे हैं (एक आवेदन नहीं), तो आपको एक मॉड्यूल में एक प्रकार लागू करने की आवश्यकता हो सकती है, शायद एक आंतरिक (उजागर नहीं) मॉड्यूल में, लेकिन आप प्रकार को उजागर करना चाहते हैं एक अलग (सार्वजनिक) मॉड्यूल। या, वैकल्पिक रूप से, आप अपने प्रकार को कई मॉड्यूल से उजागर करना चाहते हैं।
    Taskकोर में और Http.Request में Http पहली बार के लिए उदाहरण हैं, जबकि Json.Encode.Value और Json.Decode.Value जोड़ी बाद का एक उदाहरण है।

    आप इसे केवल तभी कर सकते हैं जब आप अन्यथा प्रकार अपारदर्शी रखना चाहते हैं: आप निर्माण कार्यों को उजागर नहीं करते हैं। जानकारी के लिए typeनीचे के उपयोग देखें।

यह ध्यान देने योग्य है कि उपरोक्त उदाहरणों में केवल # 1 एक कंस्ट्रक्टर फ़ंक्शन प्रदान करता है। यदि आप # 1 में अपने प्रकार के उपनाम module Data exposing (Person)को उजागर करते हैं, तो यह प्रकार नाम के साथ-साथ निर्माण कार्य को भी उजागर करेगा।



के Usages type

  1. टैग किए गए यूनियन प्रकार को परिभाषित करें
    यह सबसे आम उपयोग-मामला है, इसका एक अच्छा उदाहरण 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)

    आप ऐसा कर सकते हैं, क्योंकि शायद मॉड्यूल को परिभाषित किया गया है

    module Maybe exposing 
        ( Maybe(Just,Nothing)

    यह भी कह सकता था

    module Maybe exposing 
        ( Maybe(..)

    इस मामले में दो बराबर हैं, लेकिन स्पष्ट रूप से एल्म में एक गुण माना जाता है, खासकर जब आप पैकेज लिख रहे हों।


  1. कार्यान्वयन विवरण को छिपाना
    जैसा कि ऊपर बताया गया है कि यह एक जानबूझकर पसंद है कि Maybeअन्य मॉड्यूल के लिए निर्माण कार्य दिखाई देते हैं।

    हालांकि, अन्य मामले भी हैं, जब लेखक उन्हें छिपाने का फैसला करता है। कोर में इसका एक उदाहरण हैDict । पैकेज के उपभोक्ता के रूप में, आपको Dictसीधे नोड्स के साथ पीछे और गड़बड़ करने वाले लाल / काले पेड़ के एल्गोरिथ्म का कार्यान्वयन विवरण देखने में सक्षम नहीं होना चाहिए । कंस्ट्रक्टर फ़ंक्शंस को छुपाना आपके मॉड्यूल / पैकेज के उपभोक्ता को आपके द्वारा किए गए फ़ंक्शंस के माध्यम से केवल आपके प्रकार (और फिर उन मानों को बदलना) के मूल्यों को बनाने के लिए मजबूर करता है।

    यही कारण है कि कभी-कभी इस तरह का सामान कोड में दिखाई देता है

    type Person =
        Person { name : String, age : Int }

    type aliasइस पोस्ट के शीर्ष पर परिभाषा के विपरीत , यह सिंटैक्स केवल एक कंस्ट्रक्टर फ़ंक्शन के साथ एक नया "यूनियन" प्रकार बनाता है, लेकिन उस कंस्ट्रक्टर फ़ंक्शन को अन्य मॉड्यूल / पैकेज से छिपाया जा सकता है।

    यदि प्रकार इस तरह से उजागर होता है:

    module Data exposing (Person)

    Dataमॉड्यूल में केवल कोड एक व्यक्ति मूल्य बना सकता है और केवल उस कोड को उस पर मिलान कर सकता है।


1

मुख्य अंतर, जैसा कि मैं इसे देखता हूं, यह है कि क्या टाइप चेकर आप पर चिल्लाएगा यदि आप "सिनोमिकल" प्रकार का उपयोग करते हैं।

निम्नलिखित फ़ाइल बनाएं, इसे कहीं रखें और चलाएं 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

0

एक aliasबस कुछ अन्य प्रकार, समान के लिए एक छोटा नाम है classOOP में। समाप्ति:

type alias Point =
  { x : Int
  , y : Int
  }

एक typeतो आप की तरह प्रकार परिभाषित कर सकते हैं (उर्फ) के बिना, आप अपने खुद के प्रकार को परिभाषित करने देगा Int, Stringअनुप्रयोग, ... आप के लिए। उदाहरण के लिए, सामान्य स्थिति में, यह एप्लिकेशन की स्थिति का वर्णन करने के लिए उपयोग कर सकता है:

type AppState = 
  Loading          --loading state
  |Loaded          --load successful
  |Error String    --Loading error

तो आप इसे viewएल्म में संभालना आसान कर सकते हैं :

-- VIEW
...
case appState of
    Loading -> showSpinner
    Loaded -> showSuccessData
    Error error -> showError

...

मुझे लगता है कि आप typeऔर के बीच का अंतर जानते हैंtype alias

लेकिन क्यों और कैसे उपयोग करें typeऔर ऐप के type aliasसाथ महत्वपूर्ण है elm, आप लोग जोश क्लेटन के लेख का संदर्भ ले सकते हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.