Hello world!

Welcome to WordPress.com. This is your first post. Edit or delete it and start blogging!

Posted in Uncategorized | 1 Comment

Haskell

A hétvégén egy kicsit belekóstoltam a tiszta funkcionális programozásba, a következő előadássorozatot követve (a Going Deep részről):
Erik Meijer: Functional Programming Fundamentals.
Egész érdekes nyelvnek tűnik a Haskell, bár az indentáció kötelezősége nem feltétlen szimpatikus. Érdekes lehet, hogy milyen refactoring eszközök léteznek hozzá.
Posted in Computers and Internet | Leave a comment

Az erőd ostroma

    Előzmény: Újabb lépcsőfokok
    Egy barátom (aki azóta PhD hallgató), még elsőévesként a következő problémába ütközött amikor C-ben kezdett el tanulni:


    Rossz eredményt adott egy (ehhez hasonló) programja:

#include <stdio.h>

int main(int argc, char ** argv)

{

    int x = 4;

    if (6 < x < 8)

    {

      puts("true");

    }

}


    Sajnos ez így kiírja azt, hogy true.
Gondolom nem kell mondanom, hogy mi a gond. (Az első összehasonlítás
eredménye a 0 szám, ami valóban kisebb mint 8.) Pedig milyen szép lenne
így kifejezni a szándékunkat!
    Természetesen készült olyan programnyelv,
amelyben az ehhez hasonló kifejezések helyesen értelmeződnek. Ilyen
például a Fortress. Azonban a Scala igencsak támogatja a nyelv
kiterjesztését, így megpróbálom ebben a bejegyzésben imitálni ezt a
tulajdonságát a Fortressnek. Megpróbálom bevenni ezt az erődöt. 🙂
    Hogyan fogjunk hozzá? Először is jó lenne egy objektumba gyűjteni,
hogy milyen volt a legutolsó összehasonlítás eredménye, valamint az
összehasonlításban szereplő érték. Ha ez megvan, akkor szépen
végigmehetünk a láncon egy ilyen objektummal. Igen ám, de ez nem lesz Boolean
értékű! Át kell még alakítani majd azzá. Az igazi az lenne, ha az első
objektummá átalakítást is meg lehetne oldani valahogy automatikusan. Mi
az amit még jó lenne tudjon? Egyszerűsített kiértékelést: ha a
kiértékelés egy pontján meghatározható a végeredmény, akkor ne
folytatódjon a kiértékelés. Lehetőleg ilyen esetben a további
kifejezések ne is hajtódjanak végre (hatékonyság, illetve mellékhatások
minimalizálása miatt).
    Nézzük mire jutottam:

/**
An object to extend the functionality of ordering. */

object
MathRelations

{
  /**
This class represents the starting point of the relation chain. */



  final
class
PreRelation[T
<%
Ordered[T]](wrapped:
=>
T)

  {
   
def
<(that:
=>
T):
ChainedRelation[T]
=
new
ChainedRelation(that,
wrapped
< that)

   
def
>(that:
=>
T):
ChainedRelation[T]
=
new
ChainedRelation(that,
wrapped
> that)

   
def
<=(that:
=>
T):
ChainedRelation[T]
=
new
ChainedRelation(that,
wrapped
<= that)

   
def
>=(that:
=>
T):
ChainedRelation[T]
=
new
ChainedRelation(that,
wrapped
>= that)

  }

  /**
This class is for the further points of the relation chain. */

 
final
class
ChainedRelation[T
<%
Ordered[T]](wrapped: =>T,
val
isTrue:
Boolean)

  {
    def
<(that:
=>
T):
ChainedRelation[T]
=
new
ChainedRelation(that,
if
(
isTrue)
(
wrapped
< that)
else
false)

    def
>(that:
=>
T):
ChainedRelation[T]
=
new
ChainedRelation(that,
if
(
isTrue)
(
wrapped
> that)
else
false)

    def
<=(that:
=>
T):
ChainedRelation[T]
=
new
ChainedRelation(that,
if
(
isTrue)
(
wrapped
<= that)
else
false)

    def
>=(that:
=>
T):
ChainedRelation[T]
=
new
ChainedRelation(that,
if
(
isTrue)
(
wrapped
>= that)
else
false)

    override
def
toString(): String =
String.valueOf(isTrue);

  }

  /**
Converts an Ordered object to a PreRelation. */

  def
toPreRelation[T
<%
Ordered[T]](o:
T) = new
PreRelation(o)

  /**
Converts a ChainedRelation to a Boolean value */

  implicit
def
toBoolean[T](r
:
ChainedRelation[T])
:
Boolean =
r.isTrue;

}

    Egyelőre
ennyi. Mit is tud ez így valójában, mi ez a sok krix-krax? Nos, az
ötlet adott volt, így a megvalósítás is viszonylag könnyen adódik. A PreRelation osztály típusparamétere egy olyan típus, mely ,,implicit módon” átalakítható Ordereddé. Az egyetlen konstruktor paraméterét wrappednek neveztem el, ennek a típusa olyan, hogy mindig kiértékelődik (=>) az azt meghatározó kifejezés, valahányszor hivatkozunk a mezőre, az így kapott kifejezés típusa pedig megegyezik a PreRelation típusparaméterével (T).

    Definiáltam néhány metódust, melyek az összehasonlításhoz használt ChainedRelation objektumokat hozzák létre. Természetesen létre lehet hozni más relációs jelekhez is (például ==, subset, …). Egyelőre azonban ennyi elég lesz.

    Nézzük hogy fest a másik osztály! Ennek a neve ChainedRelation, ugyanolyan típusparamétere van, mint az elsőnek. Azonban ennek a korábbihoz hasonló wrapped paraméter mellett egy Boolean típusú, el is mentett, nem változtatható (val) mezője is van.

    A metódusok itt is hasonlóak. A megvalósítás kissé túlbonyolítottnak tűnhet, mivel elég lenne a második paraméternél isTrue && wrapped
< that
, jellegű megoldást alkalmazni. Azonban a Scala sajátosságai miatt, ekkor lefutna a thatet meghatározó kód, elvesztenénk egy fontos tulajdonságot.

    Definiáltam egy toString()
metódust is, azonban erre nincs igazán szükség. A hibakereséshez
azonban jól jöhet (vagy épp rosszul) a hiba jellegétől függően.

    Mi maradt még? Az előrelációt készítő metódus, illetve a Boolean
értékké alakító. Előbbire még nem érdemes szavakat vesztegetni, utóbbi
viszont kissé érdekesebb. Itt szerepel egy újabb kulcsszó, az implicit.
Ezzel azt jelezhetjük, hogy ha ez a metódus látható, és van olyan
objektumunk, ami a paraméterének megfelel, akkor fusson le, ha az adott
környezetben az eredmény típusának megfelelő értékre van szükség
(legalábbis nagyvonalakban). Ez még hasznos lehet majd. 🙂

    Ideje visszatérni a toPreRelation
metódusra. Ez miért nem lehet implicit? Lenne értelme, hiszen így
anélkül lehetne használni a most elkészített eljárásunkat, hogy bármit
is írnunk kellene. Az elején be kellene importálni a MathRelations
összes metódusát és ilyen szép dolgokat művelhetnénk. Nos, ennek az oka
nem csak az, hogy bizonyos esetekben igen jelentős többletmunkát adnánk
a processzornak (létre kell hoznia új objektumokat,… ) akkor is, ha
erre nincs szükség (mert mondjuk nincs is igazi lánc), de az is, hogy
ezt nem teszi lehetővé a Scala fordító (legalábbis jelenlegi változata):

  • illegal cyclic reference involving method toPrerelation
  • implicit method toPreRelation is not
    contractive, because the implicit parameter type (T) => Ordered[T]
    is not strictly contained in the signature (T) => <error>

    Nagyjából ennyi lenne a teendőnk. Azonban nem ártana kipróbálni is. Nézzük:

import
MathRelations.{toBoolean,
toPreRelation => |}

object
testMathRelations
extends
Application

{
  def
unPureMethod()
:
Float =
{
println("Called");
2}

  def
p(x:
Boolean)
{
println(x)}

  p(|(4.0)
<= 3 >=
unPureMethod()
>= 1)

}

    Mit mutat így? Először is elérhetővé tettük a metódusainkat, sőt a hosszú nevű toPreRelation metódust át is neveztük | jellé. Eztán készítettünk egy olyan metódust, aminek van mellékhatása, kiírja azt, hogy Called. Emellett visszaadja a 2 értéket is. A p metódus egy Boolean értéket ír ki. Ezt csak azért írtam, hogy véletlenül se a toString érték alapján írjon ki valamit a println. (Érdemes lehet kipróbálni, hogy mit ír ki a program, ha nincs felüldefiniálva a ChainedRelation.toString metódus és csak simán a println-t használjuk a kiíráshoz.)

    Nyugodtan ki lehet próbálni különféle értékekkel, hátha valahol hibázik a program.

    Bizonyára feltűnt, hogy figyelmeztetéseket adott a programunk amikor lefordítottuk a tesztet. Nos ez hiba. (Viszont ha az osztályainkat nem finalként deklaráljuk, akkor nem jelentkezik.)

    Összegzés: Nagyjából
sikerült szimulálni a Fortress hasonló nyelvi elemét. Nem ugyanaz a
kényelem, de ha valakinek tetszik, akkor használhatja és nem kell attól
tartania, hogy olyan hibákba fut mint a C-s program esetében.


    Megint felmerül a kérdés, hogy merre tovább. Van egy programunk,
amit nem ártana mondjuk tesztelni. Vagy valamerre másfelé kellene
fordulni? Majd elválik. 🙂
    Addig is nem sokára megjelenik a Scala új változata is, mely néhány újabb nyelvi elemet hoz majd.


Posted in Scala | 1 Comment

Újabb lépcsőfokok



    Az előző bejegyzés is egy kedvcsináló írás volt, ez is az lesz. Akkor egy nem teljesen elmagyarázott példát is bemutattam. Lássuk mi mit csinál?

object
XmlHello
extends
Application
{

  
val
xml = (

    
<!– An xml with
comment –>

    
<hello
who=
{java.util.Locale.getDefault().getDisplayCountry()}
from=
"scala"></hello>

    
<tag attribute="value">
      
<hello who="dear
reader"
from="author"/>

    
</tag>)

  for
(
nodes
<-
xml;
//Selecting the nodes of xml
(scala.xml.Elem).

        node
<-
nodes
\\ "hello";
//Finding the nodes with label ==
"hello".

        who
<-
node
attribute
"who"
//Selecting those which has "who"
attribute.

  )

    println(node.label
+ "
"
+
who)
//Printing the label and the who
attribute value.
}

    Azt, hogy ez egy futtatható program lesz,
gondolom nem kellene megemlítenem sem. Létrehozunk egy XML
dokumentumot, melyre mutató referenciát rögtön át is adjuk egy nem
változtatható referencia tárolónak, ez lenne az amit xmlként
azonosítottunk. A Java nyelvvel ellentétben itt nem lehet később
értéket kapnia. Természetesen itt is lehetnek változó referencia
tárolók, azokat a var kulcsszóval vezethetjük be. Az XML dokumentumot ()-ek közé zártuk (a típusa pedig scala.xml.NodeBuffer). Ez a fejlesztőkörnyezet hiányossága miatt volt szükséges, enélkül nem tudta volna lefordítani. Azonban egyébként is praktikus lehet kitenni a zárójelet, nehogy véletlenül csak az XML-es megjegyzés legyen az a dokumentum amit később használhatunk.
    Az első hello tag who attribútumában megfigyelhetjük, hogy egy Scala kifejezésből veszi fel az értékét. Ez éppenséggel lehetne Java kód is, így lehet az aktuális Locale országának szépen kinéző változatát megkapni. Természetesen itt sem kötelező kiírni a csomagnevet, lehet használni az import kulcsszót a későbbi gépelés megspórolásához, az olvashatóság javításához. (Azonban kissé bonyolultabb mint Java-ban, így erről igény esetén csak később. (Például lehetővé teszi, hogy átnevezéssel hivatkozzunk valamire kódunkban.))
    Azt hiszem az XML létrehozásáról ennyi elegendő volt. Nézzük a többit!
    Ott egy ismerős for
Azonban mintha túl sok minden lenne utána. Nos, Scala-ban nincs for ciklus. Az egyébként is helyettesíthető while ciklussal szükség esetén. Helyette a fort
sokkal érdekesebben lehet használni. Be lehet járni vele különféle
szekvenciákat, szűrni lehet azokból és akár az eredmény is lehet egy
újabb szekvencia. Elég hasznos, kényelmes lehet, ha jól használja az
ember.
    Először az XML dokumentum részein haladunk végig, ezekre később a nodes aktuális értékeivel hivatkozhatunk. A nodes egyes értékei a scala.xml.Comment, scala.xml.Elem
, scala.xml.Elem típusúak, (legspeciálisabb) közös ősük a scala.xml.Node absztrakt osztály. (Igen, a változónév és a megjegyzés is elég megtévesztő) A következő lépésben ezek közül kiválasztjuk azokat, melyek hello címkével rendelkeznek valahol (akár a belsejükben). Ezt a scala.xml.Node közvetlen ősében (scala.xml.NodeSeq – a név talán mégsem volt annyira megtévesztő) definiált \\(that: String): NodeSeq metódussal tehettük meg. Dehát nem is írtunk .-ot! Nos, igen. A Scala
támogatja a metódusok olyan hívási módját is (amennyiben nulla, vagy
egy paramétere van), amely olyan mintha operátorként használnánk. Így
lényegében végtelen sok operátort használhatunk. És igen, használhatunk
olyanmetódusneveket is, amelyeket Java esetén nem (de az adott futtatókörnyezet esetében igen). Így a \\ is használható. Amit ez csinál az hasonlít az XPath lekérdező nyelv hasonló műveletére: megkeresi az adott gyökérből kiindulva az összes illeszkedő scala.xml.Node-ot. Ezeknek a node azonosítót adtuk. A következő sorban ezek közül csak azokat választjuk ki, melyeknek van who attribútuma. Ehhez a
scala.xml.Node attribute(key: String): Option[Seq[Node]] metódusát használtuk (most is pontok nélkül). A hozzá tartozó scaladoc egy kissé idejétmúlt, mivel azt írja ha nincs hozzá key attribútum, akkor nullt ad vissza. Szerencsére nem így van, mivel akkor a példánk sem működne. Amit visszaad az egy scala.Option. Ennek pontosan két leszármazottja van, a scala.Some (egy osztály) és a scala.None (egy egyke objektum). Scala fordítóval nem is lehetne több. (Azonban Java-t, vagy más nyelvet is használva ez már nincs így…) Ezt úgy érték el, hogy a scala.Option osztályt ellátták a sealed kulcsszóval, emiatt csak vele egy fordítási egységben (állományban) lévő osztályok terjeszthetik ki, ezek pedig csak a felsoroltak.
    Ami meglepő, hogy a scala.Option esetén is alkalmazható a for (a scala.None-okat kihagyja, míg a scala.Some-okat megtartja), így az értékeket a who változóban elhelyezhetjük.
    A végén már csak ki kell írnunk a node címkéjét, illetve a who változó értékét egy szóközzel elválasztva és meg is kapjuk a korábban leírt eredményt.

    Sok mindenről lehetne még írni (akár programokról (ScalaCheck, lift, ), további nyelvi elemekről (eseti osztályok, egzisztenciális típus paraméterek, generikusok, ), vagy akár elméleti alapokról (monádok, katamorfizmus, kategória elmélet, ), technológiákról (IDE használat, különböző platformokra fejlesztés, )), azonban úgy tűnik senki sem szeretné egy olyan irányba terelgetni ezt a bemutatást ami tetszene neki. A végén kénytelen leszek magam dönteni. 🙂 (Esetleg hasznosabbak lennének Fortress-szel, vagy Nemerlével kapcsolatos bejegyzések?)
    Végül egy fejtörő: Mit csinál a következő programrészlet?

(""
/: (1 to
20)) ( (_,_).
_1
+ "_"
)
 
Nem egyszerű ugye? (Nos kissé csaltam is. Ennek nagy részéről még nem
írtam, de az egyik levelező listán előjött megoldásként és megtetszett.
A Perl kedvelők örömére idekerült. ;-))

Folytatás itt

Posted in Scala | Leave a comment

Az első lépcsőfokok


    Az emberek folyamatosan keresik a leginkább
megfelelő eszközt a problémák megoldásához. A programozás esetén a
programozási nyelv kiválasztása egy örök vitatéma. Ez a bejegyzés nem
fogja eldönteni ezt a vitát. Mindössze egy ,,új” szereplőt mutat be.
Ez a szereplő a Scala.
Nézzük mit nyújthat ez a nyelv?

  • Nyílt forrású, természetesen a hozzá tartozó könyvtár is.
  • Több platformon is képes futni. (A leginkább támogatott a JVM-es, de működik .NET-en is.)
  • Kompatibilitás (ezáltal rengeteg korábbi megoldást probléma nélkül használhatunk vele). De nem minden áron.
  • Objektumorientált megközelítés.
  • Egyszerűbb XML kezelés.
  • Funkcionális programozási lehetőség.
  • Generikus programozás, könyvtárak. (Bár kissé eltér a szemantikája a Java által követettől.)
  • Átgondolt tervek alapján készítették.
  • Rugalmas fejlesztési módszer (és néhány a hibára lehetőséget adó konstrukció elhagyása).
  • Jelzések (annotation) használata.
  • Tömör (például eseti osztályok (case class)).
  • Típusinformációk kikövetkeztetése.
  • Kötelező kiírni a felüldefiniálást (override) jelző kulcsszót (override).
  • Nagyszerű közösség. (Régi-új megoldásokkal. Igyekeznek mindenhonnan a legjobbakat ,,összelopkodni”)

Ennyit a marketingről… Mi az amitől mégsem annyira kerek ez az egész? (Szubjektív.)

  • A
    típust a változó neve után adhatjuk meg. (A Pascalt kedvelőknek
    gondolom épp ez tetszik. Az is igaz, hogy a típusinformációk
    kikövetkeztetése és a lehetőség, hogy a metódus hívások elől a .-ot,
    argumentumai körül a ()-et bizonyos esetekben elhagyhatjuk, így egy
    szeparátor jel mindenképp szükséges, az pedig, hogy így a típus a
    végére kerül végülis nem olyan nagy gond.)

  • A generikusok jelzésénél nem a <, > párost, hanem a [, ] párost használhatjuk.
  • A tömbindexelő operátor a ( ), nem pedig a [ ].
  • Mozgó
    célpont: a gyakori kiadások nem teljesen kompatibilisek a korábbiakkal.
    (Azért általában 1-2 kiadás idejére még bent marad elavultként
    (deprecated) mielőtt eltávolítanák.)

  • Viszonylag kicsi fejlesztői közösség.
  • A
    fejlesztő környezet(ek) még nem az igazi(ak). (Legalábbis aki már
    hozzászokott az Eclipse, Netbeans, … tudású eszközökhöz ezt kevésnek
    találhatja.)

  • Operátorok
    használatának lehetősége. (Néha jól jön, de az implicit átalakításokkal
    (implicit conversion) együtt kissé kockázatosnak érzem.) Szerencsére
    van precedencia, illetve megadható, hogy jobb-asszociatív legyen.

  • Nem kötelező ellenőrzött kivételek (checked exception).
  • Az, hogy a ; nem kötelező nem igazán tudom megítélni mennyire zavaró. Néha jó, ám néha bosszantó hibák forrása is lehet.

    Összességében nem rossz nyelv. Nem egyszerű, de miután ráérez az ember a stílusára kedvelhetővé válik.
Kiknek
szól ez a cikk(sorozat)? Nos, nem a többféle programozási nyelvet jól
ismerőknek. Nekik valószínűleg az Ocaml, LISP, vagy a Haskell után nem
sok újat mutathat. Inkább az objektumorientált fejlesztésben
gyakorlottabbak a célközönség.

Alapok

    A bemutatott példákat az Eclipse-hez készült aktuális (jelenleg beta) kiterjesztés (plugin) segítségével fordítom, futtatom. (A Netbeans rajongók egy-két független kiterjesztés közül válogathatnak: ScalaBeans, Scala Editor (Erlybird)) Ehhez néhány segítség:
A
telepítés a szokásos, a Help/Software Updates/Find and
Install…/Search for new features to install/New Remote Site… részen
az URL: http://lamp.epfl.ch/~mcdirmid/scala.update . Eztán már
telepíthető, csak ki kell választanunk és el kell fogadnunk a licencet.
A használatáról a  A futtatás szintén szokásos.
    Amennyiben nem
eclipse-et használunk a próbálkozásainkhoz, akkor biztosan tetszeni fog
a scala parancs. Ezzel nem csak parancsállományszerűen (script)
futtathatjuk programunkat, de egy interaktív környezetben ki is
próbálhatjuk a képességeit.

Az elmaradhatatlan világunkat üdvözlő program:

object
Hello

{

  def
main(args
:
Array[String])
:
Unit =
println("Hello
world"
)

}

Vagy, ha ez jobban tetszik:

object
HelloSimple
extends
Application

{

  println("Hello
world!"
)

}


    Kezdőknek azt hiszem az utóbbi sokkal
érthetőbb, különösen ha a bőbeszédű Java változatával hasonlítjuk
össze. Kezdjük is ezzel. Az object kulcsszóval egyke (singleton)
osztály egyetlen példányát és magát az osztályt is deklaráljuk. Az
scala.Application egy osztálya a hozzácsomagolt könyvtárnak. (A
scaladoc sajnos nem jön elő F2-re, azonban ha fölé megyünk egérrel
megtudhatjuk, hogy mire is jó.) Ezzel lehet egyerűen futtatható
programot készíteni. Mivel a scala nem tartalmaz statikus (static)
metódusokat (method), emiatt minden ilyesmit az egyke objektumokkal
kell megoldanunk.
    Ekkor nem kell a main metódust elkészítenünk,
de ha nem tesszük (mint ahogy erre nincs is most szükség), akkor a
parancssori paramétereket nem tudjuk felhasználni.
    A kiírást
végző metódus a scala.Predef.println(x: Any), ami a
scala.Console.println(x: Any), ami végül Java platformon a
java.lang.System.out.println(Object x) metódust hívja meg.
    Nézzük
akkor az első példát. Itt ugyanúgy egy egyke objektum létrehozásával
kezdünk, mely alapértelmezésben a scala.ScalaObject
kiterjesztését/implementálását jelenti. Hasonlóan a Java nyelvhez itt
is egy String tömböt paraméterként kapó, visszatérési értékkel nem
rendelkező main metódussal tudjuk jelezni, hogy mit szeretnénk majd
futtatni. Gondolom kiderült, hogy ezek közül mi melyiknek felel meg
(String tömg: Array[String], nincs visszatérési érték, de terminálhat
(szándékunk szerint fog is): Unit). Eztán a metódus implementációját
adjuk meg az = jel után. A println(x: Any) ugyanaz mint korábban, ; itt
sem szükséges utána.

    Nézzünk egy feleslegesen túlbonyolított üdvözlő programot:

object
XmlHello
extends
Application
{

   val
xml = (

    
<!– An xml with
comment –>

    
<hello
who=
{java.util.Locale.getDefault().getDisplayCountry()}
from=
"scala"></hello>

    
<tag attribute="value">

      
<hello who="dear
reader"
from="author"/>

    
</tag>)

  for
(
nodes
<-
xml;
//Selecting the nodes of xml
(scala.xml.Elem).

        node
<-
nodes
\\ "hello";
//Finding the nodes with label ==
"hello".

        who
<-
node
attribute
"who"
//Selecting those which has "who"
attribute.

  )

    println(node.label
+ "
"
+
who)
//Printing the label and the who
attribute value.

}

    Amit
nálam kiír az a következő:

hello
Magyarország

hello
dear reader

    Ennek
a példának a részletesebb magyarázata
azonban a következők részekre marad.

    Felmerülhet a kérdés, hogy mire is jó
igazán? Nos erre -egy általános nyelv esetében természetesen- sok
válasz adható. Egyes területekhez kapcsolódó speciális nyelvek
kialakításától matematikai problémák formalizálásán és megoldásán át
webes, adatbázisos alkalmazások készítésén keresztül szinte bármire.
Kinek mihez van kedve?

Folytatás: itt.

Posted in Scala | 2 Comments