Warning: strpos() [function.strpos]: Empty needle in /home/dealer/kasat/pkg/cahir/web/html/lib/plugins/translation2/action.php on line 53

Warning: Cannot modify header information - headers already sent by (output started at /home/dealer/kasat/pkg/cahir/web/html/lib/plugins/translation2/action.php:53) in /home/dealer/kasat/pkg/cahir/web/html/inc/actions.php on line 163
erlang:macro [Krystian Bacławski Wiki]
 

Preprocesor Erlanga

Dyrektywy

-include(File).
-include_lib(File).
-file(FileName, LineNumber).
  • Dołączanie dowolnych plików.
  • Dołączanie biblioteki.
  • Zmiana nazwy pliku i numeru linii.

Predefiniowane makra

?MODULE
?MODULE_STRING
?FILE
?LINE
?MACHINE

Lista predefiniowanych makr:

  • Nazwa bieżącego modułu jako atom.
  • Nazwa bieżącego modułu jako ciąg znakowy.
  • Nazwa pliku bieżącego modułu.
  • Numer bieżącej linii.
  • Nazwa wirtualnej maszyny.

Makra jako stałe

Specyfikacja:

  • Deklaracja stałej.
-define(NAME, Replacement).
  • Użycie stałej w programie.
?NAME

Przed przejściem preprocesora

-define(TIMEOUT, 1000).
 
receive
  after ?TIMEOUT -> ok
end

Po przejściu preprocesora

receive
  after 1000 -> ok
end

Makra jako funkcje

-define( Name( Var1, ..., VarN ), Replacement ).
 
?Name( Val1, ..., ValN )

Specyfikacja:

  • Deklaracja makra funkcyjnego.
  • Użycie makra funkcyjnego w programie.

Przed przejściem preprocesora

-define(DATE(Day, Month, Year), { {d, Day}, {m, Month}, {y, Year} } ).
-define(DATE(Day, Month), { {d, Day}, {m, Month}, {y, 2012} } ).
 
?DATE(16, 3, 2010).
?DATE(9, 3).

Po przejściu preprocesora

{ {d, 16}, {m, 3}, {y, 2010} }.
{ {d, 9}, {m, 3}, {y, 2012} }.

Dyrektywy warunkowe

-undef(Macro).
-ifdef(Macro).
-ifndef(Macro).
-else.
-endif.

Lista predefiniowanych makr:

  • Anulowanie deklaracji makra.
  • Przetwarzaj poniższy blok linii, wtw Macro jest zdefiniowane.
  • Przetwarzaj poniższy blok linii, wtw Macro nie jest zdefiniowane.
  • Występuje za dyrektywą ifdef lub ifndef. Jeśli warunek z poprzedzającej dyrektywy był fałszywy to wykonaj poniższy blok.
  • Zakończenie bloku.

Stringifying i różności

Stringyfing: Często przy odpluskwianiu programu przydaje się możliwość drukowania wyrażeń. Można je otrzymać przekształcając preprocesorem wyrażenie na ciąg znakowy.

Jeśli do paramteru makra dodamy jako prefiks ciąg ?? to parametr zostanie przekształcony na ciąg znakowy.

Przykład:

-define( VALUE(Call), io:format("~p = ~p~n", [??Call, Call] )
test1() ->
?VALUE( length( [1, 2, 3] ) ).
 
1> test:test1().
"length( [1, 2, 3] )" = 3

Moduły

Podstawy

Specyfikacja:

  • Moduł musi posiadać co najmniej dwie dyrektywy. Jedna określa nazwę modułu, druga listę eksportowanych funkcji.
  • Moduł może posiadać dodatkowe atrybuty takie jak autor czy data.
  • Atrybut wersja może być używany przy aktualizacji modułów.
  • Moduł może importować do lokalnej przestrzeni nazw funkcje z innych modułów.

Przykład:

-module(demo).
-export([double/1]).
-author("Krystian Baclawski").
-date({2010,3,16}).
-vsn(1.0).
 
double( Value ) ->
  times( Value, 2 ).
 
times( X, Y ) ->
  X * Y.

Dyrektywy modułów

-import( Module, FuncList ).
-behaviour( Behaviour ).
-author( Author ).
-date( Date ).
-vsn( VersionNumber ).
-record( Name, Fields ).

Lista opcjonalnych dyrektyw modułów:

  • Importowanie funkcji do lokalnej przestrzeni nazw.
  • Moduł wykorzystywanego szablonu.
  • Autor modułu.
  • Data skojarzona z modułem (właściwie w dowolnej postaci).
  • Wersja modułu. Zwyczajowo jako float.
  • Rekord zdefiniowany przez moduł i udostępniany na zewnątrz.

Inspekcja modułów

Czego można się dowiedzieć o dowolnym module?:

  • Każdy moduł ma zaimplementowaną funkcję module_info.
  • Można podejrzeć wszystkie składowe modułu.
  • Można odpytać czy moduł zawiera funkcję o podanej nazwie i arności.

Przykład:

1> demo:module_info().
[{exports,[{double,1},{module_info,0},{module_info,1}]},
 {imports,[]},
 {attributes,[{author,"Krystian Baclawski"},
  {date,[{2010,3,16}]},
  {vsn,[1.0]}]},
 {compile,[{options,[]},
   {version,"4.6.2"},
   {time,{2010,3,16,12,35,1}},
   {source,"/home/cahir/workspace/erlang/demo.erl"}]}]
2> erlang:function_exported(demo,double,1).
true
3> erlang:function_exported(demo,times,2).
false

Rekordy

Składnia

Co to są rekordy?

Przypomnijcie sobie z C lub z Pascala. Zbiór nazwanych elementów. Elementy mogą mieć wartości domyślne. Czasami mówi się o nich jak o krotkach nazwanych.

Po co nam rekordy?

  • Przy skomplikowanych krotkach, kiedy nie chcemy pamiętać na którym miejscu jest jaki element.
  • A co jeśli chcemy rozszerzyć krotkę o dodatkowy element? Wszystkie funkcje korzystające z dopasowania wzorca mogą się rozsypać.
  • Może ktoś pomyli kolejność elementów w krotce.

Deklaracja i wewnętrzna reprezentacja

Deklaracja rekordu jest w istocie specjalną dyrektywą preprocesora.

-record(Name, {Field1 [= Value1],
               ...
               FieldN [= ValueN]}).

Wartości domyślne są opcjonalne. Nazwy pól rekordu to atomy.

Przykład

-module(records).
-record(person, {name, surname = "Nowak", age = 0}).
-record(birthday, {person, month, day}).

Inspekcja rekordów

2> record_info(fields, person).
[name,surname,age]
3> record_info(size, person).
4

Operacje na rekordach

Tworzenie instancji rekordu

#Name{ Field1 = Expr1, ..., FieldK = ExprK }
#Name{ Field1 = Expr1, ..., FieldK = ExprK, _ = ExprL }

Można określić tylko, niektóre pola rekordu – w szczególności żadnego. Twarda spacja odpowiada pozostałym polom. Pola niezainicjowane dostaną wartość w postaci atomu undefined. Pola mogą być podane w dowolnej kolejności.

Przykład

2> #person{name = "Boleslaw", surname = "Chrobry", age = "1043" }.
#person{name = "Boleslaw", surname = "Chrobry",age = "1043" }
3> #person{}.
#person{name = undefined, surname = "Nowak", age = 0}
4> #person{age=63, name="Jan"}.
#person{name = "Jan", surname = "Nowak", age = 62}
5> #person{age = 62, _ = empty}.
#person{name = empty, surname = empty, age = 62}

Selekcja i aktualizacja pól rekordu

Expr#Name.Field
  • Traktuj Expr jako rekord typu Name i wyciągnij pole Field.
#Name.Field
  • Zwróć numer pola Field w rekordzie Name.
Expr#Name{ Field1 = Expr1, ..., FieldK = ExprK }
  • Podmień odpowiednie pola w wyrażeniu Expr traktowanym jako rekord Name.

Przykład

2> Rec = #person{name="Jan",age="62"}.
#person{name = "Jan",surname = "Nowak",age = "62"}
3> #person.age.
4
4> Rec#person{name = "Grzegorz"}.
#person{name = "Grzegorz",surname = "Nowak",age = "62"}
5> is_record(Rec, person).
true
6> is_record(Rec, birthday).
false

Zagnieżdżone rekordy

Przykład

3> R1 = #person{ name = "Jan", age = 26 }.
#person{name = "Jan",surname = "Nowak",age = 26}
4> R2 = #birthday{ person = R1, month = 6, day = 10 }.
#birthday{person = #person{name = "Jan",surname = "Nowak", age = 26},
          month = 6,day = 10}
5> R2#birthday.person.
#person{name = "Jan",surname = "Nowak",age = 26}
6> R2#birthday.day.
10
7> (R2#birthday.person)#person.name.
"Jan"
8> R2#birthday{ person = (R2#birthday.person)#person{ name = "Jacek" } }.
#birthday{person = #person{name = "Jacek", surname = "Nowak",age = 26},
          month = 6,day = 10}

Rekordy w wyrażeniach

W strażniku funkcji

Selekcja pól w strażniku:

alive( P ) when P#person.age > 200 ->
  not_at_all;
alive( P ) when P#person.age > 100 ->
  probably_not;
alive( _P ) ->
  probably.

Co się stanie jeśli P#person.age nie będzie integer?

W działaniu:

3> records:alive( #person{name="Boleslaw", surname="Chrobry", age=1043} ).
not_at_all
4> records:alive( #person{name="Jan", age=62} ).
probably
5> records:alive( #person{name="Jan", age="62"} ).
not_at_all

W dopasowaniu wzorca

Rozpakowywanie rekordu w dopasowaniu wzorca

alive2( #person{ age = Age } = P ) when is_list(Age) ->
  alive2( P#person{ age = list_to_integer(Age) } );
alive2( #person{ age = Age } ) when Age > 200 ->
  not_at_all;
alive2( #person{ age = Age } ) when Age > 100 ->
  probably_not;
alive2( #person{ age = Age } ) ->
  probably.

Poniższa wersja poprawnie reaguje na ciągi znakowe w polu P#person.age:

3> records:alive2( #person{name="Boleslaw", surname="Chrobry", age="1043"} ).
not_at_all
4> records:alive2( #person{name="Jan", age=62} ).
probably
5> records:alive2( #person{name="Grzegorz", age="122"} ).
probably_not

Wewnętrzna reprezentacja rekordu

Coś co należy wiedzieć, a czego nie należy używać!

Dla spostrzegawczych:

  • czemu record_info(size,person) zwraca wartość 4?
  • czemu #person.surname zwraca wartość 3?

Rekordy to tak na prawdę krotki, w których pierwszym elementem jest atom określający nazwę rekordu.

Przykład

2> rr(records).
[person,birthday]
3> Tuple = {person, "Nullislaw", "Pointerski", 25}.
#person{name="Nullislaw",surname="Pointerski",age=25}
4> Tuple#person.name.
"Nullislaw"
5> #person.name.
2

Rekordy i powłoka

Funkcje do operacji na rekordach w powłoce:

  • rr - Zaimportuj rekordy z pliku.
  • rl - Wydrukuj listę znanych rekordów.
  • rd - Zdefiniuj nowy rekord.
  • rf - Zapomnij definicję rekordu.

Przykład

1> rr(records).
[person,birthday]
2> rl().
-record(birthday,{person,month,day}).
-record(person,{name,surname = "Nowak",age = 0}).
ok
3> rd(date,{year,month,day}).
date
4> rf(birthday).
ok
5> rl().
-record(date,{year,month,day}).
-record(person,{name,surname = "Nowak",age = 0}).
ok
 
erlang/macro.txt · Last modified: 2010/05/07 22:27 by Krystian Bacławski
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-No Derivative Works 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki