08 - Vektor3D andThen compose¶
Láttuk előadáson, hogy mik is azok a case classok, most ezt fogjuk gyakorolni.
a feladat¶
Készítsünk egy Vektor3D
case classt, mely egy 3-dimenziós Double
vektort (mármint
egy 3D irányvektort) tárol!
- A mezők nevei legyenek
x
,y
,z
! - Írjunk olyan függvényt, mely kiszámítja a bejövő vektor hosszát!
- Írjunk olyan függvényt, mely inputként kap egy
v
vektort és egyc
számot és visszaadja ac * v
vektort! - Írjunk olyan függvényt, mely a két bejövő argumentum vektornak az összegét számítja ki!
- Írjunk olyan függvényt, mely ,,normalizál'' egy vektort (azaz visszaad egy ugyanolyan irányú, egység hosszú vektort)! Ha a vektor hossza túl kicsi, akkor legyen belőle nullvektor.
- Írjunk skalár szorzó függvényt, mely két bejövő vektorból elkészíti a skalárszorzatukat!
a megoldás¶
Vegyük végig a részfeladatokat egyesével, és minden részfeladat után futtassuk le a teszteket, hogy jól gondolkodtunk-e!
Hogyan készítünk el egy ilyen case classt?
1 |
|
Válasz mutatása
A vektor hossza koordinátáinak négyzetösszege a gyök alatt. Ehhez hasznos lehet
a Math
objektum sqrt
függvénye. Implementáljuk!
1 |
|
Válasz mutatása
Persze ebben a nyelvben is a szorzás erősebb művelet, mint az összeadás, ezért nem kell kitegyünk zárójeleket.
Itt érdemes megismerjük az import
egy újabb használatát:
- a forrásfile elején egy
import Math.sqrt
sorral elérjük, hogy azsqrt
függvény elé ne kelljen kiírni, hogy Math (ugyanakkor pl. aMath.abs
elé továbbra is ki kell ekkor), - egy
import Math.*
sornak pedig az lesz a hatása, hogy aMath
objektumon belüli minden függvényt elég csak a nevén nevezni, Math és egyéb prefixek nélkül.
Persze ez nem csak a Mathra, hanem bármelyik csomag bármelyik objektumára igaz. Ezt persze olyankor érdemes megtenni, ha standard nevű a függvény és/vagy többször használjuk, úgy nem rontja az olvashatóságot mások számára, viszont rövidebb lesz, könnyebben feldolgozható emberi szemmel.
A számmal szorzás koordinátánként kell megszorozza a vektort a megadott számmal és visszaadni azt az új vektort, amit így kapunk. Hogyan implementáljuk le?
1 |
|
Válasz mutatása
Két vektort koordinátánként adunk össze. Hogyan tegyük ezt?
1 2 |
|
Válasz mutatása
A normalizáló függvényt úgy írjuk meg, hogy ha a Vektor hossza 1e-10
vagy kisebb, akkor
nullvektort adjunk vissza, egyébként pedig osszuk le a vektor hosszával.
Érdemes ehhez a vektor hosszát kirakni egy értékbe. Használjuk fel a számmal szorzó és
a hosszt számító függvényeket!
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Válasz mutatása
Végül ebben a feladatblokkban utolsóként, írjunk skalár szorzó függvényt: két vektor skalárszorzatát úgy kapjuk, hogy összeszorozzuk páronként az azonos koordinátákat és ezt a (most három) szorzatot összeadjuk.
1 2 |
|
Válasz mutatása
kompozíció¶
Ha megfigyeljük, a skaláris szorzatból és a gyökvonásból elő lehet állítani a hossz kiszámítását: önmagával kell skalárszorozni a vektort, majd gyököt vonni az eredményből. Újraírhatjuk ez alapján akár a hossz függvényt. Hogyan?
1 2 |
|
Válasz mutatása
Ez, mikor is több függvény egymásba helyettesítésével, végül a ,,legalsó'' függvénybe az argumentumok
beírásával áll elő az eredmény, fontos elem funkcionális programozásban is; egy imperatív
nyelven vélhetően kb. így csinálnánk. Azonban a funkcionális paradigmában, így pl. Scalában is,
nem csak a ,,built-in'' primitív típusok, mint pl. az Int
ek közt vannak előre definiálva
műveletek, mint pl. az Intek közti összeadás, szorzás, hanem a függvények között is.
Egy ilyen az andThen
: ha f: T => U
egy függvény és g: U => V
egy másik függvény
(tehát az a fontos, hogy f
output típusa ugyanaz legyen - vagy szűkebb -, mint g
input típusa), akkor f andThen g
lesz az a T => V
függvény, ami az input x
-re elébb
kiszámítja f(x)
értékét, majd az eredményt behelyettesíti g
-be, vagyis
(f andThen g)(x) = g(f(x))
. Vannak, akiknek az andThen
felírás könnyebben értelmezhető,
mert így vizuálisan is kijön, hogy előbb f
-et, majd utána g
-t számítjuk ki.
Most ez nem könnyít meg nagyon semmit, mert az első függvényünk, f
, nem az u
-t várja,
hanem u,u
-t, így nem tudjuk azt írni, hogy skalarSzorzat andThen sqrt
: sajnos az andThen
csak egyváltozós függvényekre van értelmezve, így a skalarSzorzat andThen
részre már
problémázik a fordító, hogy nem tudja értelmezni, amit szeretnénk tőle.
Egy megoldás az, hogy készítünk egy olyan függvényt, ami egy bejövő vektort vár, és önmagával
skalárszorozza azt (így kimenete egy Double lesz), majd ezzel kapcsoljuk össze andThen
-nel
a sqrt
függvényt. Sikerül forduló kódot írjunk, ami ezt csinálja?
1 2 |
|
1 |
|
Válasz mutatása
Jobb viszont, ha már ismerjük az andThen
függvényt, ha ismerjük a compose
függvényt is: lényegében ez egy
fordított sorrendű andThen
, f andThen g
ugyanaz, mint g compose f
. Hogy miért is van így ebből kettő..
truth is, még a matematikában sem konzisztens az, hogy egy ,,f
kör g
'' mint függvénykompozíció jelölés most
a kettő közül melyiket is jelentse.
Ha csak megfordítjuk a két függvény sorrendjét és compose
-t írunk andThen
helyett, ezt kapjuk:
1 |
|
Értjük a hibaüzenetből, hogy mi a probléma?
1 |
|