Zobrazit příspěvky

Tato sekce Vám umožňuje zobrazit všechny příspěvky tohoto uživatele. Prosím uvědomte si, že můžete vidět příspěvky pouze z oblastí Vám přístupných.


Příspěvky - zboj

Stran: 1 ... 87 88 [89] 90 91 ... 101
1321
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 18. 09. 2015, 10:22:27 »
Diskuse se zase zvrtla, tak to shrňme. Jsou tři možnosti:

Vsechny tri moznosti jsou pretypovani, tam ci onde (ta treti je pretypovani po navratu z nasobeni matice). Jediny rozdil je, ze programatori treba v Pythonu chapou jeho typy jako navzajem ruzne, zatimco typovi teoretici to (nekdy) vnimaji jako jeden typ. Jak rikam, typy maji v programovani asi 3 ruzne vyznamy:

  • Umoznuji statickou typovou kontrolu
  • Indikuji zpusob polymorfismu
  • Definuji zpusob ulozeni dat v pameti

V tom tvem tretim pripade jenom kombinujes vyznam slova "typ" 1 a 2, coz je v poradku (protoze slovo typ je zavadejici), ale neni to zadna revoluce. V Haskellu se slovo typ pouziva pro 1. vyznam, v Pythonu pro 2. vyznam, v C pro 3. vyznam (prevazne). Ve vetsine modernejsich jazyku lze kontrolovat vsechny tri vyznamy pomoci ruznych mechanismu (napr. Haskell - typove tridy umoznuji delat vyznam 2).

(I kdyz co umoznuje delat v Haskellu vyznam 3 mi neni jasne. V dobre typovanych jazycich je vyznam 3 neco jako dependency injection, prijde mi, ze je tam nejaka dualita mezi vyznamem 2 a 3 - v podstate dualita mezi typovymi tridami a daty, nebo dualita mezi interfacem a implementaci.)

Takže když mám

Kód: [Vybrat]
func f()->SquareMattix { ...; return SquareMatrix(...) }

tak je někde přetypování? Kde přesně? Možná jen přetypováním myslíme každý něco jiného. Pro mě je přetypování něco ve stylu

Kód: [Vybrat]
let m=Matrix(...); return SquareMatrix(matrix)

nebo

Kód: [Vybrat]
let m:Matrix=...; return m as? SquareMatrix

V prvním případě ale vzniká nový objekt a v tom druhém může vzniknout nil.

1322
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 18. 09. 2015, 10:13:42 »
To by byl ten případ s (implicitním) přetypováním (operator SquareMatrix()), nicméně ani to mi neumožní napsat v C++ něco jako (m1*m2).trace() (na rozdíl od Swiftu).
Jo, v C++ by bylo třeba něco jako "square(m1*m2).trace()". To není zas tak zlé.

BTW umí nějaký (jiný) jazyk toto?

Kód: [Vybrat]
func *(x:Vector,y:Vector) -> Tensor {...}
func *(x:Vector,y:Vector) -> Double {...}
func *(x:Vector,y:Vector) -> AST {...}

let p:Double = a*b // scalar product
let p:Tensor = a*b // tensor product
let p:AST = a*b // AST

Docela praktické, hlavně ten AST.

V C# lze dosáhnout v podstatě téhož tak, že násobení vrátí instanci MultiplicationResult a třída MultiplicationResult bude obsahovat implicitní konverzi na double a na Tensor. AST lze získat pomocí Expression - tj. násobení místo parametru typu T bude brát parametr typu Expression<T>.

Ve Scale se použije například (ve Scale bude asi hodně možností, jak dosáhnout téhož) trik analogický tomu s CanBuildFrom - tj. násobení bude mít implicitní parametr BuildResult[T] a vracet typ T. Takto definované násobení pak může kdokoliv (i cizí kód) rozšířit na libovolný návratový typ, případně předefinovat jeho chování pro určité návratové typy. S AST lze ve Scale pracovat pomocí maker.

Jasně, tak to umí i C++. Ale umí to ještě nějaký jazyk v době kompilace? Benchmark by asi dopadl pro C# v tomto případě špatně.

1323
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 18. 09. 2015, 07:59:08 »
To by byl ten případ s (implicitním) přetypováním (operator SquareMatrix()), nicméně ani to mi neumožní napsat v C++ něco jako (m1*m2).trace() (na rozdíl od Swiftu).
Jo, v C++ by bylo třeba něco jako "square(m1*m2).trace()". To není zas tak zlé.

BTW umí nějaký (jiný) jazyk toto?

Kód: [Vybrat]
func *(x:Vector,y:Vector) -> Tensor {...}
func *(x:Vector,y:Vector) -> Double {...}
func *(x:Vector,y:Vector) -> AST {...}

let p:Double = a*b // scalar product
let p:Tensor = a*b // tensor product
let p:AST = a*b // AST

Docela praktické, hlavně ten AST.

1324
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 18. 09. 2015, 07:41:23 »
Scalu detailně neznám, ale předpokládám, že lépe to v ní nepůjde.

Já v ní také nedělám, takže mi včera večer například nedocvaklo, že je zbytečné používat case class, když se dá matchnout normální třída třeba takto:

Kód: [Vybrat]
object MatrixCaseApp extends App {
  val m = Matrix.newMatrix(Array(Array(1.0, 2.0),Array(1.0, 2.0)))
  val n = Matrix.newMatrix(Array(Array(1.0, 2.0),Array(1.0, 2.0)))
  Matrix.multiply(m, n) match {
    case x: SquareMatrix => println(x.trace())
    case _ => println("Sorry, not a square matrix")
  }
}

To jsou ale detaily. Faktem je, že jsem si pomohl pattern matchingem, který Scala zdědila z FP větve a ne z OOP.

Pattern matching je jedno z možných řešení, ale také to je jen zakuklené přetypování.

1325
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 18. 09. 2015, 07:37:50 »
Řeší problém

... stejně idiotsky jako pokusit se přetypovat výsledek a čekat zda se nestane ClassCastException.

Mohl bych se urazit, ale proč. Furt je to lepší než to, co jsi nabídl Ty (zkontrolovat třídu a pak přetypovat), protože to co nabízíš Ty, to umí samozřejmě automaticky taky. Implicitní konverze emuluje chování programu v dynamickém jazyce. Ovšem moje druhé řešení je typově bezpečné a bez trapných obezliček ve stylu instanceof.
Proč tam je RectangleMatrix?

1326
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 18. 09. 2015, 00:40:36 »
Citace
Mít dvě implementace metody pro násobení a využít inferenci typu a polymorfismus návratového typu; není nutné nic kopírovat ani použít as, prostě se napíše (a*b).trace()

A jak dopadne vysledek prekladu/vyhodnoceni, pokud:
Kód: [Vybrat]
a = matrix(2,3); b = matrix(3,4)

Pro uplnost dodam, ze predpokladam, ze hodnoty promennych jsou znamy az za behu programu.

Běh blbě, protože použitím trace říkám, že matice je čtvercová, takže někde bouchne assert.

1327
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 17. 09. 2015, 23:14:24 »
OK, řešení č. 2, snad už projde přes komisi:

Kód: [Vybrat]
package casematrix {

abstract class Matrix(array: Array[Array[Double]]) {
  private val elements = array
  def toArray(): Array[Array[Double]] = {
    this.elements
  }
}
object Matrix {
  def newMatrix(array: Array[Array[Double]]) : Matrix = {
    if (array.length == array(0).length) new SquareMatrix(array)
    else new RectangleMatrix(array)
  }
  def multiply(first: Matrix, second: Matrix) = {
    newMatrix(first.toArray()) // dummy
  }
}

case class RectangleMatrix(array : Array[Array[Double]]) extends Matrix(array)

case class SquareMatrix(array : Array[Array[Double]]) extends Matrix(array) {
  def trace() : Float = {
    return 0; // dummy
  }
}

}

import java.lang.RuntimeException
import casematrix._

object MatrixCaseApp extends App {
  val m = Matrix.newMatrix(Array(Array(1.0, 2.0),Array(1.0, 2.0)))
  val n = Matrix.newMatrix(Array(Array(1.0, 2.0),Array(1.0, 2.0)))
  Matrix.multiply(m, n) match {
    case m @ SquareMatrix(_) => println(m.trace())
    case _ => println("Sorry, not a square matrix")
  }
}

Scalu detailně neznám, ale předpokládám, že lépe to v ní nepůjde.

1328
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 17. 09. 2015, 23:07:14 »
Diskuse se zase zvrtla, tak to shrňme. Jsou tři možnosti:

1. Konverze Matrix na SquareMatrix, vznikne nový objekt, který ale může využít "vnitřnosti" obecnější matice. V C++ by pak bylo něco jako SquareMatrix(a*b).trace() (násobení vždy vrací instanci Matrix).

2. Dynamické řešení, násobení vrací instanci Matrix nebo SquareMatrix podle rozměrů. Použití: ((a*b) as SquareMatrix).trace() (nic nového se nevytváří).

3. Mít dvě implementace metody pro násobení a využít inferenci typu a polymorfismus návratového typu; není nutné nic kopírovat ani použít as, prostě se napíše (a*b).trace() ("magii" udělá překladač v době kompilace). Nevýhody: jde to jen ve Swiftu (ze zmiňovaných jazyků) a ti jednodušší (programátoři-praktici, jak je někdo nazval :) ) to nejsou schopni pochopit. Je fakt, že příklad by šel asi vymyslet lepší.

(4. Mít jen jednu třídu, to ale není odpověď na otázku.)

1329
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 17. 09. 2015, 22:54:46 »
Kód jsem psal výše, opakovat ho nebudu.

Pro jistotu ho tedy zopakujeme, aby bylo všem jasno že takhle to nejde:
Kód: [Vybrat]
func *(m1:Matrix,m2:Matrix)->Matrix
func *(m1:Matrix,m2:Matrix)->SquareMatrix

Řeší problém

... stejně idiotsky jako pokusit se přetypovat výsledek a čekat zda se nestane ClassCastException.

Tak ať v tom mám jasno - co hlásí překladač? Pokud nic, kde je přetypování? Buď máš jinou verzi překladače, nebo jen plácáš. Nebo nevíš, co je přetypování. Doporučuju manuál ke Swiftu, sekci o inferenci typů. Jsou tam ostatně podobné příklady.

1330
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 17. 09. 2015, 22:21:38 »
V dynamickém jazyce to půjde vždy, to je jasné. Tady se řeší staticky typovaný jazyk.

Tak som oprasil c++

Kód: [Vybrat]
#include <iostream>

class Matica {
    protected:
        int riadky;
        int stlpce;
    public:
        Matica(int, int);
        Matica* sucin(Matica *);
        virtual void typ() { std::cout << "Matica " << this->riadky << ", " << this->stlpce << "\n"; }
};

class StvMatica: public Matica {
    public:
        StvMatica (int r, int s) : Matica (r, s) {}
        virtual void typ() { std::cout << "Stvorcova Matica " << this->riadky << ", " << this->stlpce << "\n"; }
};

Matica::Matica(int r, int s)
{
    this->riadky=r;
    this->stlpce=s;
}

Matica* Matica::sucin(Matica *matica)
{
    Matica *sucin;
    if (this->stlpce == matica->riadky)
        sucin = new StvMatica(matica->riadky, this->stlpce);
    else
        sucin = new Matica(matica->riadky, this->stlpce);

    return sucin;
}

int main(void)
{
    Matica *m1, *m2, *sucin;

    m1 = new Matica(3, 2);
    m2 = new Matica(2, 3);

    sucin = m1->sucin(m2);

    m1->typ();
    m2->typ();
    sucin->typ();

    return 0;
}


Unika mi nieco preco takto nie?

PS: To "overeni" je dobry kviz o CR ;)
Čtverec s obdélníkem z vedlejšího vlákna vrací úder? Uvědomuješ si, že pokud někdo přidá do Matica metodu resize, nebo něco podobného, tak máš dokonalou past, že?

U násobení se dá předpokládat, že objekt je neměnný (vrací se nová matice).

1331
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 17. 09. 2015, 22:04:20 »
Pravě že ne. Třetí cesta je polymorfismus návratové hodnoty (jde to ve Swiftu, jinak nevím, kde ještě).

Coz v podstate neni nic jineho nez pretypovani vysledku za behu (jak tu nekdo ukazal v Pythonu). Ale to je prave dusledek toho zmateni, o cem jsou typy.
Ne za běhu, ale při kompilaci. To je pravé ten rozdíl. Viz kód výše.

1332
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 17. 09. 2015, 22:03:11 »
Tak si to napiš (ve Swiftu). Jasně, je to náročné na pochopení, ale Swift to umí, funkční implementace je důkaz.

Ani na třetí pokus jste nedodal vysvětlení jak by to mělo fungovat, tedy to uzavírám s tím že neumí.

Naprasený příklad ve Scale:
Kód jsem psal výše, opakovat ho nebudu. Buď nevíš, co je polymorfismus, nebo návratová hodnota.

Neřeší zadání, to je něco úplně jiného.

1333
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 17. 09. 2015, 22:01:18 »
V dynamickém jazyce to půjde vždy, to je jasné. Tady se řeší staticky typovaný jazyk.

Tak som oprasil c++

Kód: [Vybrat]
#include <iostream>

class Matica {
    protected:
        int riadky;
        int stlpce;
    public:
        Matica(int, int);
        Matica* sucin(Matica *);
        virtual void typ() { std::cout << "Matica " << this->riadky << ", " << this->stlpce << "\n"; }
};

class StvMatica: public Matica {
    public:
        StvMatica (int r, int s) : Matica (r, s) {}
        virtual void typ() { std::cout << "Stvorcova Matica " << this->riadky << ", " << this->stlpce << "\n"; }
};

Matica::Matica(int r, int s)
{
    this->riadky=r;
    this->stlpce=s;
}

Matica* Matica::sucin(Matica *matica)
{
    Matica *sucin;
    if (this->stlpce == matica->riadky)
        sucin = new StvMatica(matica->riadky, this->stlpce);
    else
        sucin = new Matica(matica->riadky, this->stlpce);

    return sucin;
}

int main(void)
{
    Matica *m1, *m2, *sucin;

    m1 = new Matica(3, 2);
    m2 = new Matica(2, 3);

    sucin = m1->sucin(m2);

    m1->typ();
    m2->typ();
    sucin->typ();

    return 0;
}


Unika mi nieco preco takto nie?

PS: To "overeni" je dobry kviz o CR ;)

To je OK, ale nejde napsat (m1*m2).trace(), vlastně jde teď jen o to, že v některých jazycích to jde bez přetypování. V C++ ale ne...

1334
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 17. 09. 2015, 21:01:56 »
Naprasený příklad ve Scale:

Kód: [Vybrat]
package matrix {
class Matrix(array: Array[Array[Double]]) {
  private val elements = array
  def toArray(): Array[Array[Double]] = {
    this.elements
  }
  def isSquareMatrix() : Boolean = {
    val numRows = this.elements.length
    for (subArray <- this.elements) {
      if (subArray.length != numRows) return false
    }
    return true
  }
}

class SquareMatrix(array : Array[Array[Double]]) extends Matrix(array) {
  def trace() : Float = {
    return 0; // dummy
  }
}
}

import java.lang.RuntimeException
import matrix._
object MatrixApp extends App {
  implicit def toSquareMatrix(m: Matrix) : SquareMatrix = {
    if (!m.isSquareMatrix()) throw new RuntimeException("Not a square matrix!")
    return new SquareMatrix(m.toArray())
  }
 
  val m = new Matrix(Array(Array(1.0, 2.0),Array(1.0, 2.0, 3.0)));
  println(m.trace())
}

Implicitní ve Scale umožňuje volat metody třídy SquareMatrix ad hoc, což je lepší než drátem do oka, ale samozřejmě to znamená, že se bude znovu a znovu kontrolovat, zda na to má nárok.

Problém ale je, co s tím dál. Pro matematické problémy typu počítání s maticemi je OOP extrémně nevhodné. Matice není nic jiného než dvourozměrné pole čísel a jako taková nepotřebuje žádné metody, stačí sada funkcí, které pracují nad dvourozměrnými poli, jestli je matice čtvercová nebo ne, je jednoduchý test a stačí ho udělat jenom jednou a pak už výpočet prostě ví, že je ve větvi, kde se dá pracovat se čtvercovou maticí anebo není.

Suma sumárum, pokud to měl být příklad, byl dost nevhodný a pokud fakt autor potřebuje řešit matice, moje rada je se na celé OOP vykašlat. Nehledě na to, že knihoven pro práci s maticemi budou mraky.
Přesně k tomu to vede, vykašlat se na OOP. Matice jsou ještě jednoduché, větší sranda je s tenzory a operacemi nad nimi. Jde to napsat objektově, ale spíš přes protokoly než dědičnost. Příklad je ostatně ve vedlejším vlákně o čtvercích a rovnoběžnících, kde je řešení přes protokoly to nejjednodušší (a nejefektivnější).

1335
Vývoj / Re:Násobení matic a automatické přetypování
« kdy: 17. 09. 2015, 20:27:45 »
Třetí cesta je polymorfismus návratové hodnoty (jde to ve Swiftu, jinak nevím, kde ještě).

Už jsme si ukázali že ne. Jestliže v metodě sedí trpaslík a podle své momentální nálady vyhazuje ven instanci Matrix nebo instanci SquareMatrix, tak je polymorfismus návratové hodnoty nepoužitelný.

Tak si to napiš (ve Swiftu). Jasně, je to náročné na pochopení, ale Swift to umí, funkční implementace je důkaz.

Stran: 1 ... 87 88 [89] 90 91 ... 101