Erlang 21 - 2. Sequential Programming

2 अनुक्रमिक प्रोग्रामिंग




erlang

2 अनुक्रमिक प्रोग्रामिंग

२.१ एर्लांग खोल

अधिकांश ऑपरेटिंग सिस्टम में कमांड दुभाषिया या शेल होता है, यूनिक्स और लिनक्स में कई होते हैं, विंडोज में कमांड प्रॉम्प्ट होता है। Erlang का अपना शेल होता है जहाँ Erlang कोड के बिट्स को सीधे लिखा जा सकता है, और मूल्यांकन किया जा सकता है कि क्या होता है (STDLIB में shell(3) मैनुअल पेज देखें)।

अपने ऑपरेटिंग सिस्टम और टाइपिंग erl में शेल या कमांड इंटरप्रेटर शुरू करके एरलांग शेल (लिनक्स या यूनिक्स में) शुरू करें। आपको कुछ इस तरह दिखाई देगा।

% erl
Erlang R15B (erts-5.9.1) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9.1  (abort with ^G)
1>

टाइप "2 + 5." शेल में और फिर Enter (गाड़ी वापसी) दबाएँ। ध्यान दें कि आप बताए गए शेल को पूर्ण विराम के साथ समाप्त करके कोड दर्ज कर रहे हैं "।" और एक गाड़ी वापसी।

1> 2 + 5.
7
2>

जैसा कि दिखाया गया है, एरलैंग शेल उन पंक्तियों को दर्ज करता है जिन्हें दर्ज किया जा सकता है, (1> 2> के रूप में) और यह सही ढंग से कहता है कि 2 + 5 7. है। यदि आप शेल में लेखन गलतियाँ करते हैं, तो आप बैकस्पेस कुंजी से हटा सकते हैं। जैसा कि ज्यादातर गोले में होता है। शेल में कई और संपादन कमांड हैं (देखें tty - A command line interface ERTS उपयोगकर्ता गाइड में tty - A command line interface )।

(ध्यान दें कि निम्नलिखित उदाहरणों में शेल द्वारा दिए गए कई लाइन नंबर अनुक्रम से बाहर हैं। यह इसलिए है क्योंकि यह ट्यूटोरियल अलग-अलग सत्रों में लिखा और कोड-परीक्षण किया गया था)।

यहाँ थोड़ी अधिक जटिल गणना है:

2> (42 + 77) * 66 / 3.
2618.0

सामान्य अंकगणित (देखें Expressions ) के रूप में, ब्रैकेट, गुणन ऑपरेटर "*" और डिवीजन ऑपरेटर "/" के उपयोग पर ध्यान दें।

Erlang सिस्टम और Erlang शेल को बंद करने के लिए Control-C दबाएं।

निम्न आउटपुट दिखाया गया है:

BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
       (v)ersion (k)ill (D)b-tables (d)istribution
a
%

Erlang सिस्टम को छोड़ने के लिए "a" टाइप करें।

एर्लांग प्रणाली को बंद करने का एक और तरीका है, halt() प्रवेश करके halt() :

3> halt().
% 

2.2 मॉड्यूल और कार्य

यदि आप केवल शेल से कोड चला सकते हैं, तो प्रोग्रामिंग भाषा का अधिक उपयोग नहीं होता है। तो यहाँ एक छोटा सा एर्लांग कार्यक्रम है। एक उपयुक्त पाठ संपादक का उपयोग करके tut.erl नामक फ़ाइल में दर्ज करें। फ़ाइल का नाम tut.erl महत्वपूर्ण है, और यह भी कि यह उसी निर्देशिका में है जहाँ आपने erl शुरू किया था)। यदि आप भाग्यशाली हैं तो आपके संपादक के पास एक एरलैंग मोड है जो आपके लिए अपने कोड को अच्छी तरह से दर्ज करना और प्रारूपित करना आसान बनाता है (टूल उपयोगकर्ता गाइड में The Erlang mode for Emacs देखें), लेकिन आप इसके बिना पूरी तरह से प्रबंधित कर सकते हैं। यहाँ कोड दर्ज करना है:

-module(tut).
-export([double/1]).

double(X) ->
    2 * X.

यह अनुमान लगाना मुश्किल नहीं है कि यह कार्यक्रम संख्याओं के मूल्य को दोगुना करता है। कोड की पहली दो पंक्तियों को बाद में वर्णित किया गया है। हमें कार्यक्रम संकलित करें। यह एक एरलैंग शेल में निम्नानुसार किया जा सकता है, जहां c मतलब संकलन है:

3> c(tut).
{ok,tut}

{ok,tut} अर्थ है कि संकलन ठीक है। यदि यह "त्रुटि" कहता है, तो इसका मतलब है कि आपके द्वारा दर्ज पाठ में कुछ गलती है। अतिरिक्त त्रुटि संदेश एक विचार देता है कि क्या गलत है इसलिए आप पाठ को संशोधित कर सकते हैं और फिर कार्यक्रम को फिर से संकलित करने का प्रयास कर सकते हैं।

अब कार्यक्रम चलाएं:

4> tut:double(10).
20

उम्मीद के मुताबिक, 10 का डबल 20 है।

अब कोड की पहली दो लाइनों पर वापस आते हैं। Erlang प्रोग्राम फाइलों में लिखे जाते हैं। प्रत्येक फ़ाइल में एक Erlang मॉड्यूल होता है । मॉड्यूल में कोड की पहली पंक्ति मॉड्यूल का नाम है ( Modules देखें):

-module(tut).

इस प्रकार, मॉड्यूल को ट्यूट कहा जाता है। पूर्ण विराम पर ध्यान दें "।" पंक्ति के अंत में। मॉड्यूल को संग्रहीत करने के लिए जो फाइलें उपयोग की जाती हैं, उनका नाम मॉड्यूल के समान ही होना चाहिए, लेकिन विस्तार के साथ ".erl"। इस स्थिति में फ़ाइल का नाम tut.erl । किसी अन्य मॉड्यूल में फ़ंक्शन का उपयोग करते समय, सिंटैक्स module_name:function_name(arguments) का उपयोग किया जाता है। तो निम्न का अर्थ है मॉड्यूल tut में कॉल फ़ंक्शन double "10" तर्क के साथ।

4> tut:double(10).

दूसरी पंक्ति कहती है कि मॉड्यूल tut में एक फ़ंक्शन होता है जिसे double कहा जाता है, जो एक तर्क (हमारे उदाहरण में X ) लेता है:

-export([double/1]).

दूसरी पंक्ति यह भी कहती है कि इस फ़ंक्शन को मॉड्यूल tut बाहर से बुलाया जा सकता है। इसके बारे में बाद में। फिर से, "ध्यान दें।" पंक्ति के अंत में।

अब एक अधिक जटिल उदाहरण के लिए, एक संख्या का भाज्य। उदाहरण के लिए, 4 का भाज्य 4 * 3 * 2 * 1 है, जो 24 के बराबर है।

tut1.erl नामक फ़ाइल में निम्नलिखित कोड दर्ज करें:

-module(tut1).
-export([fac/1]).

fac(1) ->
    1;
fac(N) ->
    N * fac(N - 1).

तो यह एक मॉड्यूल है, जिसे tut1 कहा जाता है जिसमें एक फ़ंक्शन होता है जिसे fac> कहा जाता है, जो एक तर्क लेता है, tut1

पहला भाग कहता है कि 1 का भाज्य 1 है।

fac(1) ->
    1;

ध्यान दें कि यह भाग अर्धविराम के साथ समाप्त होता है ";" यह इंगित करता है कि आने वाले फ़ंक्शन का अधिक होना है।

दूसरा भाग कहता है कि N का फैक्टर N - 1 के एन के गुणक से गुणा है:

fac(N) ->
    N * fac(N - 1).

ध्यान दें कि यह भाग एक "के साथ समाप्त होता है।" यह कहते हुए कि इस कार्य के और हिस्से नहीं हैं।

फ़ाइल संकलित करें:

5> c(tut1).
{ok,tut1}

और अब 4 के भाज्य की गणना करें।

6> tut1:fac(4).
24

यहां मॉड्यूल tut1 में फ़ंक्शन फंक्शन fac> को तर्क 4 साथ कहा जाता है।

एक फ़ंक्शन में कई तर्क हो सकते हैं। आइए हम मॉड्यूल tut1 को दो संख्याओं को गुणा करने के लिए फ़ंक्शन के साथ विस्तारित करते हैं:

-module(tut1).
-export([fac/1, mult/2]).

fac(1) ->
    1;
fac(N) ->
    N * fac(N - 1).

mult(X, Y) ->
    X * Y.

ध्यान दें कि -export लाइन का विस्तार इस जानकारी के साथ करना आवश्यक है कि दो तर्कों के साथ एक और फ़ंक्शन mult है।

संकलित करें:

7> c(tut1).
{ok,tut1}

नए फ़ंक्शन को आज़माएं:

8> tut1:mult(3,4).
12

इस उदाहरण में संख्या पूर्णांक हैं और कोड N , X और Y में कार्यों में तर्क को चर कहा जाता है। चर को एक बड़े अक्षर से शुरू करना चाहिए ( Variables देखें)। चर के उदाहरण Number , ShoeSize और Age

2.3 परमाणु

एटम एर्लांग में एक अन्य डेटा प्रकार है। परमाणु एक छोटे अक्षर से शुरू होते हैं ( Atom देखें), उदाहरण के लिए, charles , centimeter और inch । परमाणु केवल नाम हैं, और कुछ नहीं। वे चर की तरह नहीं हैं, जिनका मूल्य हो सकता है।

अगले प्रोग्राम को tut2.erl नाम की फ़ाइल में दर्ज करें)। यह इंच से सेंटीमीटर और इसके विपरीत परिवर्तित करने के लिए उपयोगी हो सकता है:

-module(tut2).
-export([convert/2]).

convert(M, inch) ->
    M / 2.54;

convert(N, centimeter) ->
    N * 2.54.

संकलित करें:

9> c(tut2).
{ok,tut2}

परीक्षा:

10> tut2:convert(3, inch).
1.1811023622047243
11> tut2:convert(7, centimeter).
17.78

बिना किसी स्पष्टीकरण के दशमलव (फ्लोटिंग पॉइंट नंबर) की शुरूआत पर ध्यान दें। उम्मीद है कि आप इससे निपट सकते हैं।

आइए देखें कि क्या होता है अगर centimeter या inch अलावा कुछ और convert फ़ंक्शन में प्रवेश किया जाता है:

12> tut2:convert(3, miles).
** exception error: no function clause matching tut2:convert(3,miles) (tut2.erl, line 4)

convert फ़ंक्शन के दो भागों को इसके खंड कहा जाता है। जैसा कि दिखाया गया है, miles या तो खंड का हिस्सा नहीं है। Erlang सिस्टम किसी भी क्‍लास से मेल नहीं खा सकता है इसलिए एक त्रुटि संदेश function_clause को लौटाया जाता है। शेल त्रुटि संदेश को अच्छी तरह से प्रारूपित करता है, लेकिन शेल की इतिहास सूची में त्रुटि टपल को सहेजा जाता है और शेल कमांड v/1 द्वारा आउटपुट किया जा सकता है:

13> v(12).
{'EXIT',{function_clause,[{tut2,convert,
                                [3,miles],
                                [{file,"tut2.erl"},{line,4}]},
                          {erl_eval,do_apply,6,
                                    [{file,"erl_eval.erl"},{line,677}]},
                          {shell,exprs,7,[{file,"shell.erl"},{line,687}]},
                          {shell,eval_exprs,7,[{file,"shell.erl"},{line,642}]},
                          {shell,eval_loop,3,
                                 [{file,"shell.erl"},{line,627}]}]}}

२.४ नल

अब tut2 कार्यक्रम शायद ही अच्छी प्रोग्रामिंग शैली है। विचार करें:

tut2:convert(3, inch).

इसका मतलब यह है कि 3 इंच में है? या इसका मतलब यह है कि 3 सेंटीमीटर में है और इसे इंच में बदलना है? एर्लांग में चीजों को अधिक समझने के लिए चीजों को एक साथ समूहित करने का एक तरीका है। इन्हें टुपल्स कहा जाता है और घुंघराले कोष्ठक से घिरा होता है, "{" और "}"।

तो, {inch,3} 3 इंच और {centimeter,5} को दर्शाता है, 5 सेंटीमीटर को दर्शाता है। अब हम एक नया प्रोग्राम लिखते हैं जो सेंटीमीटर को इंच और इसके विपरीत परिवर्तित करता है। tut3.erl नामक फ़ाइल में निम्नलिखित कोड दर्ज करें:

-module(tut3).
-export([convert_length/1]).

convert_length({centimeter, X}) ->
    {inch, X / 2.54};
convert_length({inch, Y}) ->
    {centimeter, Y * 2.54}.

संकलन और परीक्षण:

14> c(tut3).
{ok,tut3}
15> tut3:convert_length({inch, 5}).
{centimeter,12.7}
16> tut3:convert_length(tut3:convert_length({inch, 5})).
{inch,5.0}

लाइन 16 पर ध्यान दें कि 5 इंच सेंटीमीटर में बदल जाता है और फिर से वापस आ जाता है और फिर से मूल मूल्य पर वापस जाता है। अर्थात्, एक फ़ंक्शन का तर्क किसी अन्य फ़ंक्शन का परिणाम हो सकता है। विचार करें कि रेखा 16 (ऊपर) कैसे काम करती है। फ़ंक्शन {inch,5} को दिए गए तर्क को पहले convert_length के पहले हेड क्लॉज, convert_length({centimeter,X}) खिलाफ मिलान किया जाता है। यह देखा जा सकता है कि {centimeter,X} {inch,5} मेल नहीं खाता (सिर "->" से पहले थोड़ा सा है)। यह विफल हो रहा है, आइए अगले क्लॉज़ के सिर की कोशिश करें, जो है convert_length({inch,Y}) । यह मेल खाता है, और Y को मान 5 मिलता है।

Tuples में दो से अधिक भाग हो सकते हैं, वास्तव में जितने चाहें उतने हिस्से, और किसी भी मान्य Erlang शब्द को शामिल करें । उदाहरण के लिए, दुनिया के विभिन्न शहरों के तापमान का प्रतिनिधित्व करने के लिए:

{moscow, {c, -10}}
{cape_town, {f, 70}}
{paris, {f, 28}}

Tuples में आइटमों की एक निश्चित संख्या होती है। टपल में प्रत्येक वस्तु को एक तत्व कहा जाता है । टपल {moscow,{c,-10}} , तत्व 1 moscow और तत्व 2 {c,-10} । यहाँ c सेल्सियस और f फारेनहाइट का प्रतिनिधित्व करता है।

2.5 सूची

जबकि समूह की चीजें एक साथ होती हैं, चीजों की सूची का प्रतिनिधित्व करना भी आवश्यक है। Erlang में सूचियाँ चौकोर कोष्ठक से घिरी होती हैं, "[" और "]"। उदाहरण के लिए, दुनिया के विभिन्न शहरों के तापमान की एक सूची हो सकती है:

[{moscow, {c, -10}}, {cape_town, {f, 70}}, {stockholm, {c, -4}},
 {paris, {f, 28}}, {london, {f, 36}}]

गौर करें कि यह सूची इतनी लंबी थी कि यह एक पंक्ति में नहीं बैठती थी। इससे कोई फर्क नहीं पड़ता, एर्लैंग सभी "समझदार स्थानों" पर लाइन ब्रेक की अनुमति देता है, लेकिन उदाहरण के लिए, परमाणुओं, पूर्णांकों और अन्य के बीच में नहीं।

सूचियों के हिस्सों को देखने का एक उपयोगी तरीका है, "|" का उपयोग करके। यह शेल का उपयोग करके एक उदाहरण द्वारा सबसे अच्छा समझाया गया है:

17> [First |TheRest] = [1,2,3,4,5].
[1,2,3,4,5]
18> First.
1
19> TheRest.
[2,3,4,5]

सूची के पहले तत्वों को बाकी सूची से अलग करने के लिए, | प्रयोग किया जाता है। First को मूल्य 1 और TheRest को मूल्य मिला है [2,3,4,5]।

एक और उदाहरण:

20> [E1, E2 | R] = [1,2,3,4,5,6,7].
[1,2,3,4,5,6,7]
21> E1.
1
22> E2.
2
23> R.
[3,4,5,6,7]

यहाँ आप का उपयोग देखें | सूची से पहले दो तत्वों को पाने के लिए। यदि आप सूची में तत्वों की तुलना में सूची से अधिक तत्व प्राप्त करने का प्रयास करते हैं, तो एक त्रुटि वापस आ जाती है। बिना किसी तत्व के सूची के विशेष मामले पर ध्यान दें, []:

24> [A, B | C] = [1, 2].
[1,2]
25> A.
1
26> B.
2
27> C.
[]

पिछले उदाहरणों में, पुराने लोगों के पुन: उपयोग के बजाय नए चर नामों का उपयोग किया जाता है: First , TheRest , E1 , E2 , R , A , B , और C इसका कारण यह है कि एक चर को केवल एक बार उसके संदर्भ (दायरे) में एक मूल्य दिया जा सकता है। इसके बारे में बाद में।

निम्न उदाहरण दिखाता है कि किसी सूची की लंबाई कैसे पता करें। tut4.erl नामक फ़ाइल में निम्नलिखित कोड दर्ज करें:

-module(tut4).

-export([list_length/1]).

list_length([]) ->
    0;    
list_length([First | Rest]) ->
    1 + list_length(Rest).

संकलन और परीक्षण:

28> c(tut4).
{ok,tut4}
29> tut4:list_length([1,2,3,4,5,6,7]).
7

स्पष्टीकरण:

list_length([]) ->
    0;

एक खाली सूची की लंबाई स्पष्ट रूप से 0 है।

list_length([First | Rest]) ->
    1 + list_length(Rest).

पहले तत्व के साथ एक सूची की लंबाई First और शेष तत्व Rest की लंबाई 1 + है।

(केवल उन्नत पाठक: यह पूंछ पुनरावर्ती नहीं है, इस कार्य को लिखने का एक बेहतर तरीका है।)

सामान्य तौर पर, टुपल्स का उपयोग किया जाता है जहां "रिकॉर्ड" या "स्ट्रक्चर्स" का उपयोग अन्य भाषाओं में किया जाता है। इसके अलावा, सूचियों का उपयोग विभिन्न आकारों के साथ चीजों का प्रतिनिधित्व करते समय किया जाता है, अर्थात जहां लिंक की गई सूचियों का उपयोग अन्य भाषाओं में किया जाता है।

Erlang में एक स्ट्रिंग डेटा प्रकार नहीं है। इसके बजाय, स्ट्रिंग्स को यूनिकोड वर्णों की सूची द्वारा दर्शाया जा सकता है। इसका अर्थ यह है कि सूची [97,98,99] "एबीसी" के बराबर है। एरलैंग शेल "चतुर" है और यह अनुमान लगाता है कि आप किस सूची का अर्थ रखते हैं और इसे उसी रूप में आउटपुट करते हैं जो सोचते हैं कि यह सबसे उपयुक्त रूप है, निम्न के लिए:

30> [97,98,99].
"abc"

2.6 मैप्स

मानचित्र मूल्य संघों की कुंजी का एक सेट है। इन संघों को "# {" और "}" के साथ समझाया गया है। 42 "मान" से एक संघ बनाने के लिए:

> #{ "key" => 42 }.
#{"key" => 42}

आइए कुछ दिलचस्प विशेषताओं का उपयोग करके एक उदाहरण के साथ सीधे गहरे अंत में कूदें।

निम्न उदाहरण दिखाता है कि संदर्भ रंग और अल्फा चैनलों के नक्शे का उपयोग करके अल्फा सम्मिश्रण की गणना कैसे करें। color.erl नामक फ़ाइल में कोड दर्ज करें:

-module(color).

-export([new/4, blend/2]).

-define(is_channel(V), (is_float(V) andalso V >= 0.0 andalso V =< 1.0)).

new(R,G,B,A) when ?is_channel(R), ?is_channel(G),
                  ?is_channel(B), ?is_channel(A) ->
    #{red => R, green => G, blue => B, alpha => A}.

blend(Src,Dst) ->
    blend(Src,Dst,alpha(Src,Dst)).

blend(Src,Dst,Alpha) when Alpha > 0.0 ->
    Dst#{
        red   := red(Src,Dst) / Alpha,
        green := green(Src,Dst) / Alpha,
        blue  := blue(Src,Dst) / Alpha,
        alpha := Alpha
    };
blend(_,Dst,_) ->
    Dst#{
        red   := 0.0,
        green := 0.0,
        blue  := 0.0,
        alpha := 0.0
    }.

alpha(#{alpha := SA}, #{alpha := DA}) ->
    SA + DA*(1.0 - SA).

red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) ->
    SV*SA + DV*DA*(1.0 - SA).
green(#{green := SV, alpha := SA}, #{green := DV, alpha := DA}) ->
    SV*SA + DV*DA*(1.0 - SA).
blue(#{blue := SV, alpha := SA}, #{blue := DV, alpha := DA}) ->
    SV*SA + DV*DA*(1.0 - SA).

संकलन और परीक्षण:

> c(color).
{ok,color}
> C1 = color:new(0.3,0.4,0.5,1.0).
#{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3}
> C2 = color:new(1.0,0.8,0.1,0.3).
#{alpha => 0.3,blue => 0.1,green => 0.8,red => 1.0}
> color:blend(C1,C2).
#{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3}
> color:blend(C2,C1).
#{alpha => 1.0,blue => 0.38,green => 0.52,red => 0.51}

यह उदाहरण कुछ स्पष्टीकरण देता है:

-define(is_channel(V), (is_float(V) andalso V >= 0.0 andalso V =< 1.0)).

पहले मैक्रो is_channel को गार्ड परीक्षणों में मदद करने के लिए परिभाषित किया गया है। यह केवल यहां सुविधा के लिए और वाक्यविन्यास अव्यवस्था को कम करने के लिए है। मैक्रोज़ के बारे में अधिक जानकारी के लिए, The Preprocessor देखें।

new(R,G,B,A) when ?is_channel(R), ?is_channel(G),
                  ?is_channel(B), ?is_channel(A) ->
    #{red => R, green => G, blue => B, alpha => A}.

फ़ंक्शन new/4 एक नया मानचित्र शब्द बनाता है और कुंजी को red , green , blue और alpha को प्रारंभिक मान से संबद्ध करने देता है। इस मामले में, 0.0 और 1.0 के बीच केवल फ्लोट वैल्यू की अनुमति है, जैसा कि प्रत्येक तर्क के लिए ?is_channel/1 मैक्रो द्वारा सुनिश्चित किया गया है। नया नक्शा बनाते समय केवल => ऑपरेटर को अनुमति दी जाती है।

new/4 द्वारा बनाए गए किसी भी रंग शब्द पर blend/2 को कॉल करके, परिणामी रंग की गणना दो मानचित्र शब्दों द्वारा निर्धारित की जा सकती है।

पहली बात blend/2 परिणामी अल्फा चैनल की गणना करना है:

alpha(#{alpha := SA}, #{alpha := DA}) ->
    SA + DA*(1.0 - SA).

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

यह फ़ंक्शन red/2 , blue/2 और green/2

red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) ->
    SV*SA + DV*DA*(1.0 - SA).

यहां अंतर यह है कि प्रत्येक मानचित्र तर्क में दो कुंजी के लिए एक चेक बनाया जाता है। अन्य कुंजियों को अनदेखा किया जाता है।

अंत में, हम blend/3 में परिणामी रंग वापस करते हैं:

blend(Src,Dst,Alpha) when Alpha > 0.0 ->
    Dst#{
        red   := red(Src,Dst) / Alpha,
        green := green(Src,Dst) / Alpha,
        blue  := blue(Src,Dst) / Alpha,
        alpha := Alpha
    };

Dst मानचित्र को नए चैनल मानों के साथ अद्यतन किया गया है। किसी नए मान के साथ मौजूदा कुंजी को अद्यतन करने के लिए वाक्यविन्यास := ऑपरेटर के साथ है।

2.7 मानक मॉड्यूल और मैनुअल पेज

Erlang में कई मानक मॉड्यूल हैं जो आपको चीजें करने में मदद करते हैं। उदाहरण के लिए, मॉड्यूल io में कई फ़ंक्शन होते हैं जो स्वरूपित इनपुट / आउटपुट करने में मदद करते हैं। मानक मॉड्यूल के बारे में जानकारी देखने के लिए, कमांड erl -man का उपयोग ऑपरेटिंग शेल या कमांड प्रॉम्प्ट में किया जा सकता है (जैसा कि आपने erl शुरू किया था)। ऑपरेटिंग सिस्टम शेल कमांड आज़माएं:

% erl -man io
ERLANG MODULE DEFINITION                                    io(3)

MODULE
     io - Standard I/O Server Interface Functions

DESCRIPTION
     This module provides an  interface  to  standard  Erlang  IO
     servers. The output functions all return ok if they are suc-
     ...

यदि यह आपके सिस्टम पर काम नहीं करता है, तो दस्तावेज को Erlang / OTP रिलीज़ में HTML के रूप में शामिल किया गया है। आप दस्तावेज़ीकरण को HTML के रूप में भी पढ़ सकते हैं या इसे www.erlang.se (वाणिज्यिक Erlang) या www.erlang.org (ओपन सोर्स) साइटों में से किसी एक से PDF के रूप में डाउनलोड कर सकते हैं। उदाहरण के लिए, एरलांग / OTP रिलीज़ R9B के लिए:

http://www.erlang.org/doc/r9b/doc/index.html

2.8 टर्मिनल के लिए आउटपुट लिखना

उदाहरणों में स्वरूपित आउटपुट करने में सक्षम होना अच्छा है, इसलिए अगला उदाहरण io:format फ़ंक्शन का उपयोग करने का एक सरल तरीका दिखाता है। अन्य सभी निर्यात किए गए कार्यों की तरह, आप शेल में io:format फ़ंक्शन का परीक्षण कर सकते हैं:

31> io:format("hello world~n", []).
hello world
ok
32> io:format("this outputs one Erlang term: ~w~n", [hello]).
this outputs one Erlang term: hello
ok
33> io:format("this outputs two Erlang terms: ~w~w~n", [hello, world]).
this outputs two Erlang terms: helloworld
ok
34> io:format("this outputs two Erlang terms: ~w ~w~n", [hello, world]).
this outputs two Erlang terms: hello world
ok

फ़ंक्शन format/2 (अर्थात, दो तर्कों के साथ format ) दो सूची लेता है। पहले वाला लगभग हमेशा "" के बीच लिखी गई सूची है। यह सूची इस प्रकार छपी है, सिवाय इसके कि प्रत्येक ~ w को दूसरी सूची से क्रम में लिए गए शब्द से बदल दिया जाता है। प्रत्येक ~ n को एक नई लाइन से बदल दिया जाता है। io:format/2 फ़ंक्शन स्वयं ही परमाणु को वापस लौटाता है यदि सब कुछ योजना के अनुसार होता है। एरलैंग में अन्य कार्यों की तरह, यदि कोई त्रुटि होती है तो यह क्रैश हो जाता है। यह एरलांग में कोई गलती नहीं है, यह एक जानबूझकर नीति है। Erlang में त्रुटियों को संभालने के लिए परिष्कृत तंत्र हैं जो बाद में दिखाए गए हैं। एक अभ्यास के रूप में, io:format दुर्घटना बनाने की कोशिश करें, यह मुश्किल नहीं होना चाहिए। लेकिन ध्यान दें कि हालांकि io:format क्रैश हो जाता है, Erlang शेल स्वयं क्रैश नहीं होता है।

2.9 एक बड़ा उदाहरण

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

%% This module is in file tut5.erl

-module(tut5).
-export([format_temps/1]).

%% Only this function is exported
format_temps([])->                        % No output for an empty list
    ok;
format_temps([City | Rest]) ->
    print_temp(convert_to_celsius(City)),
    format_temps(Rest).

convert_to_celsius({Name, {c, Temp}}) ->  % No conversion needed
    {Name, {c, Temp}};
convert_to_celsius({Name, {f, Temp}}) ->  % Do the conversion
    {Name, {c, (Temp - 32) * 5 / 9}}.

print_temp({Name, {c, Temp}}) ->
    io:format("~-15w ~w c~n", [Name, Temp]).
35> c(tut5).
{ok,tut5}
36> tut5:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},
{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
moscow          -10 c
cape_town       21.11111111111111 c
stockholm       -4 c
paris           -2.2222222222222223 c
london          2.2222222222222223 c
ok

यह प्रोग्राम कैसे काम करता है, यह देखने से पहले, ध्यान दें कि कोड में कुछ टिप्पणियां जोड़ी गई हैं। एक टिप्पणी एक% -चायक के साथ शुरू होती है और लाइन के अंत तक जाती है। यह भी देखें कि -export([format_temps/1]). पंक्ति में केवल फ़ंक्शन format_temps/1 । अन्य फ़ंक्शन स्थानीय फ़ंक्शन हैं, अर्थात, वे मॉड्यूल tut5 बाहर से दिखाई नहीं देते हैं।

यह भी देखें कि शेल से प्रोग्राम का परीक्षण करते समय, इनपुट दो लाइनों में फैला हुआ है क्योंकि लाइन बहुत लंबी थी।

जब format_temps को पहली बार कहा जाता है, तो City को मान {moscow,{c,-10}} और Rest की सूची बाकी है। तो फंक्शन print_temp(convert_to_celsius({moscow,{c,-10}})) को कहा जाता है।

यहाँ एक फ़ंक्शन कॉल है जैसा कि convert_to_celsius({moscow,{c,-10}}) फ़ंक्शन print_temp के तर्क के रूप में है। जब फ़ंक्शन कॉल इस तरह से नेस्टेड होते हैं, तो वे अंदर से बाहर निष्पादित (मूल्यांकन) करते हैं। अर्थात्, पहले convert_to_celsius({moscow,{c,-10}}) का मूल्यांकन किया जाता है, जो मान {moscow,{c,-10}} क्योंकि तापमान पहले से ही सेल्सियस में है। फिर print_temp({moscow,{c,-10}}) का मूल्यांकन किया जाता है। फ़ंक्शन convert_to_celsius convert_length पिछले उदाहरण में convert_length फ़ंक्शन के समान तरीके से काम करता है।

print_temp बस io:format कॉल करता है io:format ऊपर वर्णित के समान तरीके से io:format । ध्यान दें कि ~ -15 w 15 की फ़ील्ड लंबाई (चौड़ाई) के साथ "टर्म" प्रिंट करने के लिए कहता है और इसे सही ठहराने के लिए छोड़ दिया गया है। (देखें io(3) ) STDLIB में मैनुअल पेज।

अब format_temps(Rest) को बाकी सूची के साथ एक तर्क के रूप में कहा जाता है। चीजों को करने का यह तरीका अन्य भाषाओं के लूप निर्माण के समान है। (हां, यह पुनरावृत्ति है, लेकिन आपको चिंता न करने दें।) इसलिए समान format_temps फ़ंक्शन को फिर से कॉल किया जाता है, इस बार City को मान {cape_town,{f,70}} और उसी प्रक्रिया को पहले भी दोहराया जाता है। यह तब तक किया जाता है जब तक कि सूची खाली नहीं हो जाती है, यह [] है, जो पहले क्लॉज format_temps([]) का मिलान करने का कारण बनता है। यह बस ( ok ) परमाणु परिणाम देता है, इसलिए कार्यक्रम समाप्त होता है।

2.10 मिलान, गार्ड और चर के दायरे

इस तरह की सूचियों में अधिकतम और न्यूनतम तापमान का पता लगाना उपयोगी हो सकता है। ऐसा करने के लिए कार्यक्रम का विस्तार करने से पहले, आइए सूची में तत्वों के अधिकतम मूल्य को खोजने के लिए कार्यों को देखें:

-module(tut6).
-export([list_max/1]).

list_max([Head|Rest]) ->
   list_max(Rest, Head).

list_max([], Res) ->
    Res;
list_max([Head|Rest], Result_so_far) when Head > Result_so_far ->
    list_max(Rest, Head);
list_max([Head|Rest], Result_so_far)  ->
    list_max(Rest, Result_so_far).
37> c(tut6).
{ok,tut6}
38> tut6:list_max([1,2,3,4,5,7,4,3,2,1]).
7

पहले ध्यान दें कि दो कार्यों का एक ही नाम है, list_max । हालांकि, इनमें से प्रत्येक एक अलग संख्या में तर्क (पैरामीटर) लेता है। एर्लैंग में इन्हें पूरी तरह से अलग कार्य माना जाता है। जहाँ आपको इन कार्यों के बीच अंतर करने की आवश्यकता है, आप नाम / एरीटी लिखते हैं, जहाँ नाम फ़ंक्शन का नाम है और Arity तर्कों की संख्या है, इस मामले में list_max/1 और list_max/2

इस उदाहरण में आप एक सूची "मान" लेकर चलते हैं, इस स्थिति में Result_so_far list_max/1 बस मानता है कि सूची का अधिकतम मूल्य सूची का प्रमुख है और सूची के बाकी हिस्सों और सूची के प्रमुख के मूल्य के साथ list_max/2 को कॉल list_max/2 । ऊपर में यह list_max([2,3,4,5,7,4,3,2,1],1) । यदि आपने एक खाली सूची के साथ list_max/1 का उपयोग करने की कोशिश की या इसे किसी ऐसी चीज के साथ उपयोग करने की कोशिश की, जो एक सूची नहीं है, तो आप एक त्रुटि का कारण list_max/1 । ध्यान दें कि एर्लांग दर्शन उनके द्वारा होने वाले फ़ंक्शन में इस प्रकार की त्रुटियों को संभालने के लिए नहीं है, लेकिन कहीं और ऐसा करने के लिए है। इसके बारे में बाद में।

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

गार्ड में कुछ उपयोगी ऑपरेटर हैं:

  • <से कम है
  • > से अधिक
  • == बराबर
  • > = अधिक या बराबर
  • = <कम या बराबर
  • / = नहीं के बराबर

( Guard Sequences देखें)।

उपरोक्त प्रोग्राम को एक में बदलने के लिए जो किसी सूची में तत्व के न्यूनतम मूल्य को काम करता है, आपको केवल> के बजाय <लिखना होगा। (लेकिन फ़ंक्शन का नाम list_min बदलना बुद्धिमानी होगी।)

पहले यह उल्लेख किया गया था कि एक चर को केवल एक बार इसके दायरे में मान दिया जा सकता है। ऊपर आप देखते हैं कि Result_so_far को कई मान दिए गए हैं। यह तब तक ठीक है जब से आप हर बार list_max/2 कॉल करते हैं और आप एक नया स्कोप बनाते हैं और प्रत्येक Result_so_far को प्रत्येक स्कोप में एक भिन्न चर के रूप में मान सकते हैं।

एक वैरिएबल बनाने और देने का एक अन्य तरीका मैच ऑपरेटर = का उपयोग करके है। इसलिए यदि आप M = 5 लिखते हैं, तो M = 5 नामक एक चर M = 5 मान के साथ बनाया गया है। यदि, एक ही दायरे में, आप M = 6 लिखते हैं, तो एक त्रुटि वापस आ जाती है। इस खोल में बाहर की कोशिश करो:

39> M = 5.
5
40> M = 6.
** exception error: no match of right hand side value 6
41> M = M + 1.
** exception error: no match of right hand side value 6
42> N = M + 1.
6

मैच ऑपरेटर का उपयोग विशेष रूप से एर्लांग शब्दों को अलग करने और नए बनाने के लिए उपयोगी है।

43> {X, Y} = {paris, {f, 28}}.
{paris,{f,28}}
44> X.
paris
45> Y.
{f,28}

यहां X को मान paris और Y {f,28}

यदि आप किसी अन्य शहर के साथ फिर से वही करने की कोशिश करते हैं, तो एक त्रुटि वापस आ जाती है:

46> {X, Y} = {london, {f, 36}}.
** exception error: no match of right hand side value {london,{f,36}}

कार्यक्रमों की पठनीयता में सुधार करने के लिए चर का उपयोग किया जा सकता है। उदाहरण के लिए, ऊपर की सूची list_max/2 , आप लिख सकते हैं:

list_max([Head|Rest], Result_so_far) when Head > Result_so_far ->
    New_result_far = Head,
    list_max(Rest, New_result_far);

यह संभवतः थोड़ा स्पष्ट है।

सूची के बारे में 2.11 अधिक

याद रखें कि | ऑपरेटर का उपयोग सूची के प्रमुख को पाने के लिए किया जा सकता है:

47> [M1|T1] = [paris, london, rome].
[paris,london,rome]
48> M1.
paris
49> T1.
[london,rome]

| ऑपरेटर का उपयोग सूची में सिर जोड़ने के लिए भी किया जा सकता है:

50> L1 = [madrid | T1].
[madrid,london,rome]
51> L1.
[madrid,london,rome]

अब इसका एक उदाहरण जब सूचियों के साथ काम कर रहा है - किसी सूची के क्रम को उलट देना:

-module(tut8).

-export([reverse/1]).

reverse(List) ->
    reverse(List, []).

reverse([Head | Rest], Reversed_List) ->
    reverse(Rest, [Head | Reversed_List]);
reverse([], Reversed_List) ->
    Reversed_List.
52> c(tut8).
{ok,tut8}
53> tut8:reverse([1,2,3]).
[3,2,1]

विचार करें कि Reversed_List का निर्माण कैसे किया जाता है। यह [] के रूप में शुरू होता है, फिर क्रमिक रूप से शीर्षों को सूची से हटाकर उलट दिया जाता है और Reversed_List जोड़ा जाता है, जैसा कि निम्नलिखित में दिखाया गया है:

reverse([1|2,3], []) =>
    reverse([2,3], [1|[]])

reverse([2|3], [1]) =>
    reverse([3], [2|[1])

reverse([3|[]], [2,1]) =>
    reverse([], [3|[2,1]])

reverse([], [3,2,1]) =>
    [3,2,1]

मॉड्यूल lists में lists में हेरफेर करने के लिए कई कार्य शामिल हैं, उदाहरण के लिए, उन्हें उलटने के लिए। इसलिए लिस्ट-मैनिपुलेटिंग फंक्शन लिखने से पहले यह जांचना एक अच्छा विचार है कि क्या कोई आपके लिए पहले से नहीं लिखा है ( lists(3) मैनुअल पेज STDLIB में देखें)।

अब हम शहरों और तापमान पर वापस आते हैं, लेकिन इस बार अधिक संरचित दृष्टिकोण अपनाएं। पहले हम पूरी सूची को सेल्सियस में परिवर्तित करते हैं:

-module(tut7).
-export([format_temps/1]).

format_temps(List_of_cities) ->
    convert_list_to_c(List_of_cities).

convert_list_to_c([{Name, {f, F}} | Rest]) ->
    Converted_City = {Name, {c, (F -32)* 5 / 9}},
    [Converted_City | convert_list_to_c(Rest)];

convert_list_to_c([City | Rest]) ->
    [City | convert_list_to_c(Rest)];

convert_list_to_c([]) ->
    [].

फ़ंक्शन का परीक्षण करें:

54> c(tut7).
{ok, tut7}.
55> tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},
{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
[{moscow,{c,-10}},
 {cape_town,{c,21.11111111111111}},
 {stockholm,{c,-4}},
 {paris,{c,-2.2222222222222223}},
 {london,{c,2.2222222222222223}}]

स्पष्टीकरण:

format_temps(List_of_cities) ->
    convert_list_to_c(List_of_cities).

यहाँ format_temps/1 कॉल convert_list_to_c/1 convert_list_to_c/1 के प्रमुख को List_of_cities , यदि आवश्यक हो तो इसे सेल्सियस में परिवर्तित करता है। | ऑपरेटर का उपयोग शेष सूची में परिवर्तित (शायद) जोड़ने के लिए किया जाता है:

[Converted_City | convert_list_to_c(Rest)];

या:

[City | convert_list_to_c(Rest)];

यह तब तक किया जाता है जब तक सूची का अंत नहीं हो जाता, अर्थात सूची खाली है:

convert_list_to_c([]) ->
    [].

अब जब सूची में परिवर्तित किया जाता है, तो इसे मुद्रित करने के लिए एक फ़ंक्शन जोड़ा जाता है:

-module(tut7).
-export([format_temps/1]).

format_temps(List_of_cities) ->
    Converted_List = convert_list_to_c(List_of_cities),
    print_temp(Converted_List).

convert_list_to_c([{Name, {f, F}} | Rest]) ->
    Converted_City = {Name, {c, (F -32)* 5 / 9}},
    [Converted_City | convert_list_to_c(Rest)];

convert_list_to_c([City | Rest]) ->
    [City | convert_list_to_c(Rest)];

convert_list_to_c([]) ->
    [].

print_temp([{Name, {c, Temp}} | Rest]) ->
    io:format("~-15w ~w c~n", [Name, Temp]),
    print_temp(Rest);
print_temp([]) ->
    ok.
56> c(tut7).
{ok,tut7}
57> tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},
{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
moscow          -10 c
cape_town       21.11111111111111 c
stockholm       -4 c
paris           -2.2222222222222223 c
london          2.2222222222222223 c
ok

अब अधिकतम और न्यूनतम तापमान वाले शहरों को खोजने के लिए एक समारोह जोड़ा जाना है। निम्न कार्यक्रम ऐसा करने का सबसे कुशल तरीका नहीं है, जैसा कि आप चार बार शहरों की सूची से चलते हैं। लेकिन पहले स्पष्टता और शुद्धता के लिए प्रयास करना और केवल जरूरत पड़ने पर कार्यक्रमों को कुशल बनाना बेहतर है।

-module(tut7).
-export([format_temps/1]).

format_temps(List_of_cities) ->
    Converted_List = convert_list_to_c(List_of_cities),
    print_temp(Converted_List),
    {Max_city, Min_city} = find_max_and_min(Converted_List),
    print_max_and_min(Max_city, Min_city).

convert_list_to_c([{Name, {f, Temp}} | Rest]) ->
    Converted_City = {Name, {c, (Temp -32)* 5 / 9}},
    [Converted_City | convert_list_to_c(Rest)];

convert_list_to_c([City | Rest]) ->
    [City | convert_list_to_c(Rest)];

convert_list_to_c([]) ->
    [].

print_temp([{Name, {c, Temp}} | Rest]) ->
    io:format("~-15w ~w c~n", [Name, Temp]),
    print_temp(Rest);
print_temp([]) ->
    ok.

find_max_and_min([City | Rest]) ->
    find_max_and_min(Rest, City, City).

find_max_and_min([{Name, {c, Temp}} | Rest], 
         {Max_Name, {c, Max_Temp}}, 
         {Min_Name, {c, Min_Temp}}) ->
    if 
        Temp > Max_Temp ->
            Max_City = {Name, {c, Temp}};           % Change
        true -> 
            Max_City = {Max_Name, {c, Max_Temp}} % Unchanged
    end,
    if
         Temp < Min_Temp ->
            Min_City = {Name, {c, Temp}};           % Change
        true -> 
            Min_City = {Min_Name, {c, Min_Temp}} % Unchanged
    end,
    find_max_and_min(Rest, Max_City, Min_City);

find_max_and_min([], Max_City, Min_City) ->
    {Max_City, Min_City}.

print_max_and_min({Max_name, {c, Max_temp}}, {Min_name, {c, Min_temp}}) ->
    io:format("Max temperature was ~w c in ~w~n", [Max_temp, Max_name]),
    io:format("Min temperature was ~w c in ~w~n", [Min_temp, Min_name]).
58> c(tut7).
{ok, tut7}
59> tut7:format_temps([{moscow, {c, -10}}, {cape_town, {f, 70}},
{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
moscow          -10 c
cape_town       21.11111111111111 c
stockholm       -4 c
paris           -2.2222222222222223 c
london          2.2222222222222223 c
Max temperature was 21.11111111111111 c in cape_town
Min temperature was -10 c in moscow
ok

2.12 अगर और केस

फ़ंक्शन find_max_and_min अधिकतम और न्यूनतम तापमान का काम करता है। एक नया निर्माण, if , यहां पेश किया गया है। यदि निम्नानुसार काम करता है:

if
    Condition 1 ->
        Action 1;
    Condition 2 ->
        Action 2;
    Condition 3 ->
        Action 3;
    Condition 4 ->
        Action 4
end

ध्यान दें कि कोई "नहीं है;" end से पहले। स्थितियां गार्ड के समान ही होती हैं, अर्थात परीक्षण सफल या विफल होते हैं। एरलैंग शीर्ष पर शुरू होता है और तब तक परीक्षण करता है जब तक कि यह एक ऐसी स्थिति नहीं मिलती है जो सफल होती है। फिर यह स्थिति का अनुसरण करने वाली क्रिया का मूल्यांकन (प्रदर्शन) करता है और end से पहले अन्य सभी शर्तों और कार्यों की उपेक्षा करता है। यदि कोई स्थिति मेल नहीं खाती है, तो एक रन-टाइम विफलता होती है। एक शर्त जो हमेशा सफल होती है वह है परमाणु true । यह अक्सर एक if , अर्थ में अंतिम रूप से उपयोग किया जाता है, तो true पालन ​​करें यदि अन्य सभी स्थितियां विफल हो गई हैं।

निम्न कार्य करने के लिए एक छोटा सा कार्यक्रम है।

-module(tut9).
-export([test_if/2]).

test_if(A, B) ->
    if 
        A == 5 ->
            io:format("A == 5~n", []),
            a_equals_5;
        B == 6 ->
            io:format("B == 6~n", []),
            b_equals_6;
        A == 2, B == 3 ->                      %That is A equals 2 and B equals 3
            io:format("A == 2, B == 3~n", []),
            a_equals_2_b_equals_3;
        A == 1 ; B == 7 ->                     %That is A equals 1 or B equals 7
            io:format("A == 1 ; B == 7~n", []),
            a_equals_1_or_b_equals_7
    end.

इस कार्यक्रम का परीक्षण देता है:

60> c(tut9).
{ok,tut9}
61> tut9:test_if(5,33).
A == 5
a_equals_5
62> tut9:test_if(33,6).
B == 6
b_equals_6
63> tut9:test_if(2, 3).
A == 2, B == 3
a_equals_2_b_equals_3
64> tut9:test_if(1, 33).
A == 1 ; B == 7
a_equals_1_or_b_equals_7
65> tut9:test_if(33, 7).
A == 1 ; B == 7
a_equals_1_or_b_equals_7
66> tut9:test_if(33, 33).
** exception error: no true branch found when evaluating an if expression
     in function  tut9:test_if/2 (tut9.erl, line 5)

ध्यान दें कि tut9:test_if(33,33) कोई भी शर्त सफल नहीं होती है। यह रन टाइम एरर की ओर जाता है if_clause , यहाँ शेल द्वारा अच्छी तरह से स्वरूपित किया गया है। देखें Guard Sequences उपलब्ध कई गार्ड परीक्षण के विवरण के लिए।

case Erlang में एक और निर्माण है। स्मरण करो कि convert_length फ़ंक्शन के रूप में लिखा गया था:

convert_length({centimeter, X}) ->
    {inch, X / 2.54};
convert_length({inch, Y}) ->
    {centimeter, Y * 2.54}.

उसी कार्यक्रम को भी लिखा जा सकता है:

-module(tut10).
-export([convert_length/1]).

convert_length(Length) ->
    case Length of
        {centimeter, X} ->
            {inch, X / 2.54};
        {inch, Y} ->
            {centimeter, Y * 2.54}
    end.
67> c(tut10).
{ok,tut10}
68> tut10:convert_length({inch, 6}).
{centimeter,15.24}
69> tut10:convert_length({centimeter, 2.5}).
{inch,0.984251968503937}

दोनों case और if है वापसी मान , जो है, ऊपर के उदाहरण में case या तो लौट आए {inch,X/2.54} या {centimeter,Y*2.54} case गार्ड के उपयोग से भी व्यवहार को संशोधित किया जा सकता है। निम्नलिखित उदाहरण यह स्पष्ट करता है। यह हमें एक महीने की लंबाई बताता है, जिसे वर्ष दिया जाता है। वर्ष का पता होना चाहिए, फरवरी के बाद से एक लीप वर्ष में 29 दिन होते हैं।

-module(tut11).
-export([month_length/2]).

month_length(Year, Month) ->
    %% All years divisible by 400 are leap
    %% Years divisible by 100 are not leap (except the 400 rule above)
    %% Years divisible by 4 are leap (except the 100 rule above)
    Leap = if
        trunc(Year / 400) * 400 == Year ->
            leap;
        trunc(Year / 100) * 100 == Year ->
            not_leap;
        trunc(Year / 4) * 4 == Year ->
            leap;
        true ->
            not_leap
    end,  
    case Month of
        sep -> 30;
        apr -> 30;
        jun -> 30;
        nov -> 30;
        feb when Leap == leap -> 29;
        feb -> 28;
        jan -> 31;
        mar -> 31;
        may -> 31;
        jul -> 31;
        aug -> 31;
        oct -> 31;
        dec -> 31
    end.
70> c(tut11).
{ok,tut11}
71> tut11:month_length(2004, feb).
29
72> tut11:month_length(2003, feb).
28
73> tut11:month_length(1947, aug).
31

2.13 बिल्ट-इन फंक्शन्स (BIFs)

BIF फ़ंक्शंस हैं जो किसी कारण से Erlang वर्चुअल मशीन में अंतर्निहित हैं। बीआईएफ अक्सर कार्यक्षमता को लागू करते हैं जो असंभव है या एर्लैंग में लागू करने के लिए बहुत अक्षम है। कुछ बीआईएफ को केवल फ़ंक्शन नाम का उपयोग करके बुलाया जा सकता है लेकिन वे डिफ़ॉल्ट रूप से erlang मॉड्यूल से संबंधित हैं । उदाहरण के लिए, trunc नीचे दिए गए बीआईएफ के लिए कॉल एक कॉल के बराबर है erlang:trunc

जैसा कि दिखाया गया है, पहले यह जांचा जाता है कि क्या एक वर्ष लीप है। यदि एक वर्ष 400 से विभाज्य है, तो यह एक लीप वर्ष है। यह निर्धारित करने के लिए, पहले वर्ष को 400 से विभाजित करें और trunc किसी भी दशमलव को काटने के लिए बीआईएफ (इसके बारे में अधिक बाद में) का उपयोग करें । फिर 400 से गुणा करें और देखें कि क्या फिर से वही मान लौटा है। उदाहरण के लिए, वर्ष 2004:

2004 / 400 = 5.01
trunc(5.01) = 5
5 * 400 = 2000

2000 2004 के समान नहीं है, इसलिए 2004 400 से विभाज्य नहीं है। वर्ष 2000:

2000 / 400 = 5.0
trunc(5.0) = 5
5 * 400 = 2000

यानी एक लीप ईयर। यदि अगले trunc वर्ष 100 या 4 से विभाज्य है तो इसी तरह से अगले दो बार का मूल्यांकन करें। पहला if रिटर्न leap या not_leap , जो वेरिएबल में लैंड करता है Leap । इस चर का उपयोग feb निम्नलिखित के लिए गार्ड में किया जाता है जो case हमें बताता है कि महीना कितना लंबा है।

इस उदाहरण ने इसका उपयोग दिखाया trunc rem विभाजन के बाद बचे हुए एर्गंग ऑपरेटर का उपयोग करना आसान है , उदाहरण के लिए:

74> 2004 rem 400.
4

इसलिए लिखने के बजाय:

trunc(Year / 400) * 400 == Year ->
    leap;

यह लिखा जा सकता है:

Year rem 400 == 0 ->
    leap;

कई अन्य बीआईएफ हैं जैसे कि trunc । केवल कुछ बीआईएफ का उपयोग गार्ड में किया जा सकता है, और आप उन कार्यों का उपयोग नहीं कर सकते हैं जिन्हें आपने खुद को गार्ड में परिभाषित किया है। (देखें Guard Sequences ) (उन्नत पाठकों के लिए: यह सुनिश्चित करने के लिए है कि गार्डों का दुष्प्रभाव न हो।) आइए हम शेल में इनमें से कुछ कार्यों के साथ खेलते हैं:

75> trunc(5.6).
5
76> round(5.6).
6
77> length([a,b,c,d]).
4
78> float(5).
5.0
79> is_atom(hello).
true
80> is_atom("hello").
false
81> is_tuple({paris, {c, 30}}).
true
82> is_tuple([paris, {c, 30}]).
false

इन सभी का उपयोग गार्डों में किया जा सकता है। अब कुछ बीआईएफ के लिए जिसका उपयोग गार्ड में नहीं किया जा सकता है:

83> atom_to_list(hello).
"hello"
84> list_to_atom("goodbye").
goodbye
85> integer_to_list(22).
"22"

ये तीनों BIF ऐसे रूपांतरण करते हैं जो Erlang में करना मुश्किल (या असंभव) होगा।

2.14 उच्च-क्रम के कार्य (फंड)

अधिकांश आधुनिक कार्यात्मक प्रोग्रामिंग भाषाओं की तरह, एरलांग में उच्च-क्रम के कार्य हैं। यहां शेल का उपयोग करके एक उदाहरण दिया गया है:

86> Xf = fun(X) -> X * 2 end.
#Fun<erl_eval.5.123085357>
87> Xf(5).
10

यहां एक फ़ंक्शन को परिभाषित किया गया है जो एक संख्या के मूल्य को दोगुना करता है और इस फ़ंक्शन को एक चर में सौंपा गया है। इस प्रकार Xf(5) रिटर्न मान 10. सूचियों के साथ काम करते समय दो उपयोगी कार्य हैं foreach और map , जिन्हें निम्नानुसार परिभाषित किया गया है:

foreach(Fun, [First|Rest]) ->
    Fun(First),
    foreach(Fun, Rest);
foreach(Fun, []) ->
    ok.

map(Fun, [First|Rest]) -> 
    [Fun(First)|map(Fun,Rest)];
map(Fun, []) -> 
    [].

ये दो कार्य मानक मॉड्यूल में प्रदान किए गए हैं lists foreach एक सूची लेता है और सूची में प्रत्येक तत्व के लिए एक मजेदार लागू करता है। map एक सूची में हर तत्व के लिए एक मजेदार लागू करके एक नई सूची बनाता है। शेल पर वापस जा रहे हैं, map का उपयोग किया जाता है और सूची के प्रत्येक तत्व में 3 जोड़ने के लिए एक मजेदार है:

88> Add_3 = fun(X) -> X + 3 end.
#Fun<erl_eval.5.123085357>
89> lists:map(Add_3, [1,2,3]).
[4,5,6]

हमें (फिर से) शहरों की एक सूची में तापमान प्रिंट करें:

90> Print_City = fun({City, {X, Temp}}) -> io:format("~-15w ~w ~w~n",
[City, X, Temp]) end.
#Fun<erl_eval.5.123085357>
91> lists:foreach(Print_City, [{moscow, {c, -10}}, {cape_town, {f, 70}},
{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
moscow          c -10
cape_town       f 70
stockholm       c -4
paris           f 28
london          f 36
ok

आइए अब हम एक मजेदार को परिभाषित करते हैं जिसका उपयोग शहरों और तापमान की सूची के माध्यम से किया जा सकता है और उन सभी को सेल्सियस में बदल सकता है।

-module(tut13).

-export([convert_list_to_c/1]).

convert_to_c({Name, {f, Temp}}) ->
    {Name, {c, trunc((Temp - 32) * 5 / 9)}};
convert_to_c({Name, {c, Temp}}) ->
    {Name, {c, Temp}}.

convert_list_to_c(List) ->
    lists:map(fun convert_to_c/1, List).
92> tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},
{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
[{moscow,{c,-10}},
 {cape_town,{c,21}},
 {stockholm,{c,-4}},
 {paris,{c,-2}},
 {london,{c,2}}]

convert_to_c समारोह पहले की तरह ही है, लेकिन यहाँ यह एक मजेदार के रूप में प्रयोग किया जाता है:

lists:map(fun convert_to_c/1, List)

जब एक फ़ंक्शन को कहीं और परिभाषित किया जाता है, तो इसे एक मजेदार के रूप में उपयोग किया जाता है, इसे इस रूप में संदर्भित किया जा सकता है Function/Arity (याद रखें कि Arity = तर्कों की संख्या)। तो map -call lists:map(fun convert_to_c/1, List) में लिखा है। जैसा कि दिखाया गया है, convert_list_to_c बहुत छोटा और समझने में आसान हो जाता है।

मानक मॉड्यूल lists में एक फ़ंक्शन भी होता है sort(Fun, List) जहां Fun दो तर्कों के साथ एक मजेदार होता है। यह मज़ा लौटता है true यदि पहला तर्क दूसरे तर्क से कम है, या फिर false । सॉर्टिंग को इसमें जोड़ा गया है convert_list_to_c :

-module(tut13).

-export([convert_list_to_c/1]).

convert_to_c({Name, {f, Temp}}) ->
    {Name, {c, trunc((Temp - 32) * 5 / 9)}};
convert_to_c({Name, {c, Temp}}) ->
    {Name, {c, Temp}}.

convert_list_to_c(List) ->
    New_list = lists:map(fun convert_to_c/1, List),
    lists:sort(fun({_, {c, Temp1}}, {_, {c, Temp2}}) ->
                       Temp1 < Temp2 end, New_list).
93> c(tut13).
{ok,tut13}
94> tut13:convert_list_to_c([{moscow, {c, -10}}, {cape_town, {f, 70}},
{stockholm, {c, -4}}, {paris, {f, 28}}, {london, {f, 36}}]).
[{moscow,{c,-10}},
 {stockholm,{c,-4}},
 {paris,{c,-2}},
 {london,{c,2}},
 {cape_town,{c,21}}]

में sort मज़ा प्रयोग किया जाता है:

fun({_, {c, Temp1}}, {_, {c, Temp2}}) -> Temp1 < Temp2 end,

यहां एक अनाम चर "_" की अवधारणा पेश की गई है। यह एक वैरिएबल के लिए बस आशुलिपि है जिसे एक मान मिलता है, लेकिन मान को नजरअंदाज कर दिया जाता है। यह कहीं भी उपयुक्त नहीं, केवल फन में इस्तेमाल किया जा सकता है। Temp1 < Temp2 रिटर्न true अगर Temp1 तुलना में कम है Temp2

Original text