টাইপ এবং প্রকারের উপন্যাসের মধ্যে এলমের মধ্যে পার্থক্য?


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

আপনার শেষ অনুচ্ছেদের পয়েন্ট সম্পর্কে নিশ্চিত নয়। আপনি কীভাবে এটির নাম দিন না কেন আপনি কী তা বলার চেষ্টা করছেন?
ঝাং চেং

8
হ্যাঁ, কেবল উল্লেখ করে যে
সংকলকটি এলিয়াসিত ধরণেরটিকে

সুতরাং আপনি যখন {}রেকর্ড সিনট্যাক্স ব্যবহার করবেন , আপনি একটি নতুন টাইপ সংজ্ঞায়িত করছেন?

4
{ lat:Int, long:Int }একটি নতুন ধরণের সংজ্ঞা দেয় না। এটি ইতিমধ্যে একটি বৈধ প্রকার। type alias Location = { lat:Int, long:Int }এছাড়াও একটি নতুন ধরণের সংজ্ঞা দেয় না, এটি ইতিমধ্যে বৈধ টাইপের জন্য অন্য একটি (সম্ভবত আরও বর্ণনামূলক) নাম দেয়। type Location = Geo { lat:Int, long:Int }একটি নতুন ধরণের সংজ্ঞা দেবে ( Location)
রবার্টজ্লোবি

4
যখন কোনটি বনাম প্রকারের টাইপ ব্যবহার করা উচিত? সর্বদা টাইপ ব্যবহারের খারাপ দিকটি কোথায়?
রিচার্ড হ্যাভেন

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অন্যরকম সমস্যার সমাধান হয়। যদি আপনি ওওপি থেকে আসেন, তবে উত্তরাধিকার, অপারেটর ওভারলোডিং ইত্যাদির সাহায্যে আপনি সমস্যাটি সমাধান করেন -

পোস্ট সিস্টেমের মতো বার্তাগুলি অতিক্রম করার সময় এটি ঘটে এমন একটি সাধারণ জায়গা। আপনি যখন কোনও চিঠি প্রেরণ করেন, আপনি ডাক সিস্টেমটি সমস্ত বার্তাকে একই জিনিস হিসাবে দেখাতে চান, সুতরাং আপনাকে কেবলমাত্র ডাক সিস্টেম একবার ডিজাইন করতে হবে। এবং তদ্ব্যতীত, বার্তাটি রাউটিংয়ের কাজটি অন্তর্ভুক্ত থাকা বার্তার থেকে স্বতন্ত্র হওয়া উচিত। কেবলমাত্র যখন চিঠিটি তার গন্তব্যস্থলে পৌঁছেছে আপনি কী বার্তাটি কী তা যত্নবান হন।

একইভাবে, আমরা typeঘটতে পারে এমন বিভিন্ন ধরণের বার্তাগুলির একটি ইউনিয়ন হিসাবে সংজ্ঞায়িত করতে পারি । বলুন আমরা কলেজের শিক্ষার্থীদের মধ্যে তাদের পিতামাতার কাছে একটি বার্তা ব্যবস্থা প্রয়োগ করছি। তাই কলেজের বাচ্চারা কেবল দুটি বার্তা পাঠাতে পারে: 'আমার বিয়ারের অর্থ দরকার' এবং 'আমার অন্তর্বাস প্রয়োজন'।

type MessageHome = NeedBeerMoney | NeedUnderpants

সুতরাং এখন, যখন আমরা রাউটিং সিস্টেমটি ডিজাইন করি, তখন আমাদের ফাংশনগুলির MessageHomeধরণগুলি বিভিন্ন ধরণের বার্তাগুলি যেভাবে হতে পারে তা নিয়ে চিন্তা করার পরিবর্তে কেবল তার বাইরে চলে যেতে পারে। রাউটিং সিস্টেমের কোনও যত্ন নেই। এটা শুধুমাত্র একটি জানি দরকার MessageHome। এটি কেবল তখনই বার্তাটি তার গন্তব্য, পিতামাতার বাড়িতে পৌঁছে যায় যে এটি কী তা আপনাকে খুঁজে বের করতে হবে।

case message of
  NeedBeerMoney ->
    sayNo()
  NeedUnderpants ->
    sendUnderpants(3)

আপনি যদি এলম আর্কিটেকচারটি জানেন, আপডেট ফাংশনটি একটি দৈত্য কেস স্টেটমেন্ট because এবং বার্তাটি পাস করার সময় আমরা একক প্রকারের জন্য ইউনিয়ন প্রকারগুলি ব্যবহার করি তবে এটি কী বার্তাটি ছিল তা ঠিক তাড়িত করার জন্য কেস স্টেটমেন্ট ব্যবহার করতে পারি, সুতরাং আমরা এটির সাথে ডিল করতে পারি।


5

আমি ব্যবহারের ক্ষেত্রে ফোকাস করে এবং কনস্ট্রাক্টর ফাংশন এবং মডিউলগুলির জন্য একটি সামান্য প্রসঙ্গ সরবরাহ করে পূর্ববর্তী উত্তরগুলির পরিপূরক করি।



এর ব্যবহার type alias

  1. একটি রেকর্ডের জন্য একটি নাম এবং একটি কনস্ট্রাক্টর ফাংশন তৈরি করুন
    এটি সর্বাধিক সাধারণ ব্যবহারের ক্ষেত্রে: আপনি কোনও নির্দিষ্ট রেকর্ড বিন্যাসের জন্য একটি বিকল্প নাম এবং কনস্ট্রাক্টর ফাংশনটি সংজ্ঞায়িত করতে পারেন।

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

    প্রকারের উপন্যাসটি সংজ্ঞায়িত করা হলে নিম্নলিখিত কন্সট্রাক্টর ফাংশনটি (সিউডো কোড) বোঝায়:
    Person : String -> Int -> { name : String, age : Int }
    উদাহরণস্বরূপ আপনি যখন জসন ডিকোডার লিখতে চান তখন এটি কার্যকর হতে পারে।

    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
    

    এলমিউরোপ ২০১ Ric-তে রিচার্ড ফিল্ডম্যানের আলাপ যখন এই স্টাইলটি ব্যবহারের পক্ষে উপযুক্ত তখন এ সম্পর্কে আরও কিছু অন্তর্দৃষ্টি দিতে পারে।

  3. পুনরায় নামকরণ স্টাফ
    আপনি এটি করতে পারেন, কারণ এই উদাহরণের মতো নতুন নামগুলি পরে আপনার কোডে অতিরিক্ত অর্থ প্রদান করতে পারে

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

    মূল ক্ষেত্রে ব্যবহারের এই ধরণেরTime আরও ভাল উদাহরণ হ'ল

  4. কোনও ভিন্ন মডিউল থেকে কোনও প্রকার পুনরায় প্রকাশ করা
    যদি আপনি প্যাকেজ (কোনও অ্যাপ্লিকেশন নয়) লিখতে থাকেন তবে আপনাকে একটি মডিউলে একটি প্রকার প্রয়োগ করতে হবে, সম্ভবত কোনও অভ্যন্তরীণ (প্রকাশিত নয়) মডিউল থাকতে পারে, তবে আপনি এই প্রকারটি প্রকাশ করতে চান একটি পৃথক (সর্বজনীন) মডিউল। অথবা, বিকল্পভাবে, আপনি একাধিক মডিউল থেকে আপনার প্রকারটি প্রকাশ করতে চান।
    Taskমূল এবং Http.Request এইচটিপি- র প্রথম উদাহরণ, অন্যদিকে Json.Encode.Value এবং Json.Decode.Value যুগলটি পরবর্তীকালের উদাহরণ the

    আপনি কেবল তখনই এটি করতে পারেন যখন আপনি অন্যথায় ধরণের অস্বচ্ছ রাখতে চান: আপনি নির্মাণকারীর কার্যাদি প্রকাশ করবেন না। বিশদ জন্য typeনীচের ব্যবহার দেখুন।

এটি লক্ষণীয় যে উপরোক্ত উদাহরণগুলিতে কেবল # 1 একটি নির্মাণকারীর ফাংশন সরবরাহ করে। আপনি যদি এই জাতীয় # 1 তে আপনার টাইপ উপন্যাসটি module Data exposing (Person)প্রকাশ করেন তবে টাইপের নামটি এবং সেই সাথে কনস্ট্রাক্টর ফাংশনও প্রকাশ করা হবে।



এর ব্যবহার 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

মূল পার্থক্য, যেমনটি আমি এটি দেখতে পাচ্ছি, আপনি যদি "synomical" টাইপ ব্যবহার করেন তবে টাইপ চেকার আপনাকে চিৎকার করবে কিনা।

নিম্নলিখিত ফাইলটি তৈরি করুন, এটিকে কোথাও রেখে চালনা করুন 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মাত্র কিছু অন্য ধরনের, অনুরূপ জন্য একটি সংক্ষিপ্ত নাম classগলি হবে। সমাপ্তি:

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, আপনি ছেলেরা জোশ ক্লেটন থেকে নিবন্ধটি উল্লেখ করতে পারেন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.