- enpassant blogja
- A hozzászóláshoz be kell jelentkezni
- 1107 megtekintés
Hozzászólások
Szép, viszont az FP megvalósításban itt nem tetszik a Draw függvény rugalmatlansága: minden "származtatott" osztályt bele kell tenni az implementációba.
- A hozzászóláshoz be kell jelentkezni
Szerintem sokkal rugalmasabb a "draw" függvény az FP-ben, akár hány "draw" függvényt készíthetsz, amikbe szépen össze tudod válogatni, hogy melyik mit csinál. OOP-ben a "draw" az az FP-beli "export"-nak felel meg, de FP-ben van "draw", "print", ... akármennyi kombinációd az egyes függvényekből.
- A hozzászóláshoz be kell jelentkezni
Csak ha elbököd, megy vele a többi implementáció is: az osztályok nincsenek elszeparálva.
- A hozzászóláshoz be kell jelentkezni
Én ilyet csináltam múltkor: OOP, FP
Gyakorlatilag a függvény típus az interface, azt úgy valósítod meg ahogy akarod. Szerintem szebb, mint az OOP megoldás.
- A hozzászóláshoz be kell jelentkezni
Szerintem is. :)
Gyakorlásként megcsináltam a set függvényt, amivel változónak adhatsz értéket.
val set = (variable: Variable, value: Float, expression: Expression) =>
(context: Context) =>
{
val newContext: Context = {
case `variable` => value
case v => context(v)
}
expression(newContext)
}
...
val expression = set(d, 4f, plus(minus(multiply(divide(value(a), value(b)), value(c)), value(d)), sqrt(constant(25f))))
val context = Map(a -> 1f, b -> 2f, c -> 3f)
println(expression(context))
- A hozzászóláshoz be kell jelentkezni
A pattern match az FP specifikus?
Egyebkent gratulalok, lenyegeben feltalaltad az Erlang fuggvenyhivasi modszeret (csak a Scala syntax zajosabb es bobeszedubb - talan a megfelelo megoldas egy makro lenne, es akkor nem kellene a PartialFunction-nal sem szorakozni a kodban)! ;)
- A hozzászóláshoz be kell jelentkezni
"A pattern match az FP specifikus?"
Igen, jellemzően FP nyelvekben van, bár egyre több nyelv fogad be FP specifikus dolgokat.
"Egyebkent gratulalok, lenyegeben feltalaltad az Erlang fuggvenyhivasi modszeret"
Nem én találtam fel, hanem Martin Odersky.
"nem kellene a PartialFunction-nal sem szorakozni a kodban"
A PartialFunction-nek megvannak az előnyei:
- lekérdezhető, hogy adott inputot kezel-e,
- tetszőleges inputra képes Option választ adni,
- könnyű más PartialFunction-ökkel bővíteni a tudását,
- mivel rendes függvény, ezért az FP jóságai erre is vonatkoznak (higher order, compose, ...)
- A hozzászóláshoz be kell jelentkezni
A Haskell-féle megoldás nekem jobban tetszik amúgy :-).
Viszont ma sikerült megfogalmaznom, mit érzek, amikor Scala-ban programozok: teljesen olyan, mint annak idején Lego-val játszani. Mindenre van építőkő, és azokat kapcsolom össze szépen. Piszok jó élmény.
- A hozzászóláshoz be kell jelentkezni
Erdekes, en most az arckaparos fazisban vagyok: egyre gyakrabban anyazok a monitorra, hogy miert kell nekem hatracsavart kezzel fejen ugralni csak azert, hogy a fordito megertse, mit akarok.
Ehhez kepest konstans flow barmilyen fejlettebb dinamikus nyelvben kodolni: Erlang, Clojure, sot (nem hiszem el, de le fogom irni) Javascript!
Remelem, majd elmulik, mert jovo heten lesz egy scalas pair programmingos interjum, nem mutatna tul jo kepet, ha menet kozben a falhoz vagnam a billentyuzetet :)
- A hozzászóláshoz be kell jelentkezni
A történethez hozzátartozik, hogy az FP részét egyelőre kevéssé használom ki. Pattern matching, higher order functions, ezek vannak, de azért dominámsan imperatív vagyok.
Viszont a feladatot (kutatási téma, ha lesz eredmény, beszámolok) nagyon jól lehet actorokkal modellezni.
- A hozzászóláshoz be kell jelentkezni
Szoval megegyszer, mitol FP-specifikus a pattern match? Nem kotozkodom, komolyan erdekel, peldaul pont a Scalaban egy objektum metodusa (az unapply) teszi lehetove, hogy tetszoleges tipuson matcholj, szoval epphogy semmi koze a FP-hoz ezen a szinten. De valoban leginkabb FP nyelvekben jellemzo, viszont nem latom, miert ne lehetne akar a Java forditot kiegesziteni egy unapply-ertelmezovel. Jo kerdes persze, hogy hol venned hasznat ezutan :)
Ha a Scala Erlang lenne, akkor peldaul ez:
type ExportShape = PartialFunction[Shape, String]
val drawCircle: ExportShape = {
case Circle(point, radius) =>
s"Drawing circle at (${point.x}, ${point.y}) Radius: $radius"
}
valahogy igy nezne ki:
def drawCircle(Circle(point, radius)) =>
s"Drawing circle at (${point.x}, ${point.y}) Radius: $radius"
meg tovabb egyszerusitve:
def draw(Circle(point, radius)) =>
s"Drawing circle at (${point.x}, ${point.y}) Radius: $radius"
def draw(Rectangle(point, width, height)) =
s"Drawing rectangle at (${point.x}, ${point.y}) Width $width, Height $height"
vagyis
def draw(Circle(Point(x, y), radius)) =>
s"Drawing circle at (${x}, ${y}) Radius: $radius"
def draw(Rectangle(Point(x, y), width, height)) =
s"Drawing rectangle at (${x}, ${y}) Width $width, Height $height"
stb.
Erre batorkodtam csak celozni. Sajnos Martin megallt valahol feluton...
- A hozzászóláshoz be kell jelentkezni
Nem igazán értem mire akarsz kilyukadni. Annyira FP specifikus, mint a függvény, az immutabilitás, a higher order függvények, a lambda függvények, ... Ezek mind lehetnek OOP vagy imperatív nyelvekben is. Az FP nyelvekben jellemzően benne van a pattern matching, míg az OOP nyelvekben általában (még) nincs.
Az Erlang-os példa meg azért nem igazán illik ide, mert az Erlang egy dinamikusan típusos nyelv, míg a Scala statikusan. Nyilván sok mindent egyszerűbb (rövidebb) megírni dinamikus nyelven, mint statikuson. A statikusnak meg más előnye van. (alma-körte esete)
"Sajnos Martin megallt valahol feluton..."
Az biztos, hogy lehetne rajta javítani, de nem biztos, hogy ezt egyszerű megtenni. A PartialFunction típusát nem kell megadni, ha anomymus függvényként, paraméterként adod meg, de nevesítve már meg kell. Ez utóbbinak egyszerűsítése meg is jelent kérésként a Scala fejlesztői felé.
- A hozzászóláshoz be kell jelentkezni
Ha egy alapvetoen FP(-nek gondolt) nyelvbol elveszed a pattern matchinget, attol meg FP marad? Ha egy alapvetoen OOP(-nek gondolt) nyelvhez hozzaadod a pattern matchinget, attol FP-jellegu lesz? Tegyuk fel ugyanezt a ket kerdest mondjuk a higher order fuggvennyel is. Egyebkent nem akarok kilyukadni semmi konkretumra, csupan hangosan gondolkodtam, elnezest :)
A masik temara pedig: mi tortenne, ha irna valaki egy makrot, ami a fenti Erlang-szeru szintakszisbol automatikusan legyartana a PartialFunction tipust, atalakitana a zajmentes parameter-matchelest a fuggveny={case => } formatumra, majd a vegen compose-olna a fuggvenyeket.
Emelt szintu feladatkent pedig az egymasba agyazott pattern matchet is kibontana megfeleloen (tehat a fenti Circle(Point(x,y)) mukodhetne). Vagy ez mar tul durva?
Persze siman lehet, hogy nyitott kapukat dongetek, es valamelyik furmanyos library ezt mar reg tudja...
- A hozzászóláshoz be kell jelentkezni
"A masik temara pedig: mi tortenne, ha irna valaki egy makrot, ami a fenti Erlang-szeru szintakszisbol automatikusan legyartana a PartialFunction tipust, atalakitana a zajmentes parameter-matchelest a fuggveny={case => } formatumra, majd a vegen compose-olna a fuggvenyeket."
Én örülnék neki, ha lenne valami hasonló! :)
"Emelt szintu feladatkent pedig az egymasba agyazott pattern matchet is kibontana megfeleloen (tehat a fenti Circle(Point(x,y)) mukodhetne)"
Ez most is működik, mármint az egymásba ágyazott case class-ok.
Pl.:
val shape = Circle(Point(10, 15), 27)
shape match {
case Circle(Point(x, y), radius) => s"Match! $x, $y"
}
res0: String = Match! 10, 15
- A hozzászóláshoz be kell jelentkezni
Es tenyleg, nem tudom, miert gondoltam, hogy ez nem mukodik. Annal jobb, egy gonddal kevesebb :)
- A hozzászóláshoz be kell jelentkezni
A másik részét meg valószínűleg nem is lehet megcsinálni, mert nem lehet kitalálni az inputok típusát.
Circle input esetén ugyanúgy lehet Circle, Shape vagy Any is.
Egyébként az Any típus használatával majdnem a dinamikusság szabadságát kapod, viszont elvesztve a statikusságot, a fordítás idejű ellenőrzést.
Pl.
type PF = PartialFunction[Any, Any]
esetén, akármilyen input és outputtal használhatod, pl.:
val calc: PF = { case x: Int => x * 2 }
val drawCircle: PF = { case (Display(), Circle(Point(x, y), radius)) => s"Draw ..." }
Használata:
calc(6) // eredmény: 12
drawCircle(Display(), Circle(Point(10, 3), 24)) => s"Draw ..." } // eredmény: Draw ...
// akár ezt is lehet:
val calcOrDraw = calc orElse drawCircle
calcOrDraw(7) // eredmény: 14
calcOrDraw(Display(), Circle(Point(10, 3), 24)) // eredmény: Draw ...
- A hozzászóláshoz be kell jelentkezni
Bámulatos, mennyire túl lehet bonyolítani, ha nagyon akarja az ember :)
- A hozzászóláshoz be kell jelentkezni
Szívesen veszem, ha valamire tudsz egyszerűbb megoldást adni!
Ez így azonban csak trollkodásnak tűnik.
- A hozzászóláshoz be kell jelentkezni