Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: Sancho 22. 09. 2016, 15:24:31
-
Trochu tápu ve funkcionálním přístupu, jaký je pls rozdíl mezi map a flatMap?
-
O jaký jazyk a knihovnu jde?
Jestli jde o Stream v Javě, tak map transformuje jeden prvek na jeden prvek. flatMap transformuje každý prvek na seznam 0-N prvků a seznamy pro jednotlivé vstupní prvky pospojuje do jednoho dlouhého seznamu.
FlatMap je složenina map z prvku na seznam a "flattening" což je pospojování seznamu seznamů.
-
Trochu tápu ve funkcionálním přístupu, jaký je pls rozdíl mezi map a flatMap?
Map je kolekcí dvojic (klíč, hodnota).
FlatMap je jednoduchý seznam, ve kterém se střídají klíče a jejich hodnoty.
-
Trochu tápu ve funkcionálním přístupu, jaký je pls rozdíl mezi map a flatMap?
Map je kolekcí dvojic (klíč, hodnota).
FlatMap je jednoduchý seznam, ve kterém se střídají klíče a jejich hodnoty.
Tak to vazne neni spravna odpoved v tomhle kontextu.
Trochu tápu ve funkcionálním přístupu, jaký je pls rozdíl mezi map a flatMap?
Pseudokodem:
[1,2,3].map (*2)
[2,3,4]
["1", "21", "foo"].map (length)
[1,2,3]
Just(2).map(*2)
Just(4)
[1,2,3].flatMap (a -> [a, 2*a])
[1,2,2,4,4,3,6]
map vezme nejaky "kontejner" (ve skutecnosti neco obecnejsiho, ale tim se ted netrap), jako je List nebo Maybe, ve kterem jsou prvky typu T a na kazdy prvek aplikuje nejakou fuknci z T na K. Vysledek je ten samy druh kontejneru, ve kterem jsou prvky typu K.
flatMap na ten samy kontejner muze aplikovat funkci, ktera z prvku typu T udela kontejner prvku typu K. A vysledek se slepi opet do kontejneru typu K.
-
A to same obrazkem:
(http://reactivex.io/documentation/operators/images/map.i.png)
versus
.
.
(http://reactivex.io/documentation/operators/images/flatMap.c.png)
(obazky jsou soucasti http://reactivex.io/ ktere doporucuji okoukat)
-
obrazky se brani vlozeni, tak alespon linky:
http://reactivex.io/documentation/operators/images/map.i.png
http://reactivex.io/documentation/operators/images/flatMap.c.png
-
Map není vs. Flatmap
Flatmap je map a flatten.
Flatten funguje sám o sobě, stejně jako map.
Map vyzvedne prvek typu a, zavolá fci a->b a připojí prvek b.
Flatten vezme typ kolekce kolekcí a udělá kolekci a.
Například mám seznam klíčů a fci která vrátí Optional. Flatmap vrátí rovnou seznam bez prvků kterém jsou prázdné.
To chybí v Javě protože optional neimplementuje Stream.
-
FlatMap je v podstatě obecnější funkce než map, protože jak map, tak filter lze implementovat pomocí flatMapu.
Pseudo-Scala:
class List {
def map(function) = flatMap { item => List(function(item)) }
def filter(predicate) = flatMap { item => if (predicate(item)) List(item) else List() }
}
-
flatMap je monada ;-)
map muze produkovat seznamy seznamu, pak je problem nacpat to do reduce. flatMap to vsechno vrati v jednom seznamu, kde vsechny objekty nejsou seznamy. krome toho je to monada v Haskellu, takze tim jde simulovat I/O a imperativni programco.
map -> [0,[1],[2,[3],[4]]]
flatMap -> [0,1,2,3,4]
-
flatMap je monada ;-)
map muze produkovat seznamy seznamu, pak je problem nacpat to do reduce. flatMap to vsechno vrati v jednom seznamu, kde vsechny objekty nejsou seznamy. krome toho je to monada v Haskellu, takze tim jde simulovat I/O a imperativni programco.
map -> [0,[1],[2,[3],[4]]]
flatMap -> [0,1,2,3,4]
Dvě technické: flatMap není monáda, na to nestačí (a chtěl jsem se tomuhle při vysvětlování vyhnout, když se někdo ptá na map vs. flatmap, tak mu to nepomůže.)
Ten příklad, co jsi napsal, nedává úplně smysl. Ta věc u mapu nejde v haskellu napsat a ten výsledek flatmap ti klidně vypadne i z mapu, záleží, co na čím mapuješ.
-
flatMap je monada ;-)
map muze produkovat seznamy seznamu, pak je problem nacpat to do reduce. flatMap to vsechno vrati v jednom seznamu, kde vsechny objekty nejsou seznamy. krome toho je to monada v Haskellu, takze tim jde simulovat I/O a imperativni programco.
map -> [0,[1],[2,[3],[4]]]
flatMap -> [0,1,2,3,4]
Dvě technické: flatMap není monáda, na to nestačí (a chtěl jsem se tomuhle při vysvětlování vyhnout, když se někdo ptá na map vs. flatmap, tak mu to nepomůže.)
Ten příklad, co jsi napsal, nedává úplně smysl. Ta věc u mapu nejde v haskellu napsat a ten výsledek flatmap ti klidně vypadne i z mapu, záleží, co na čím mapuješ.
Doplnění: monáda, když už teda, by bylo "map" (jakožto funktor) spolu s "unit" a "join" (přirozené transformace), přičemž join=flatten.
-
Map je kolekcí dvojic (klíč, hodnota).
FlatMap je jednoduchý seznam, ve kterém se střídají klíče a jejich hodnoty.
Tak to vazne neni spravna odpoved v tomhle kontextu.
map vezme nejaky "kontejner" (ve skutecnosti neco obecnejsiho, ale tim se ted netrap), jako je List nebo Maybe, ve kterem jsou prvky typu T a na kazdy prvek aplikuje nejakou fuknci z T na K. Vysledek je ten samy druh kontejneru, ve kterem jsou prvky typu K.
flatMap na ten samy kontejner muze aplikovat funkci, ktera z prvku typu T udela kontejner prvku typu K. A vysledek se slepi opet do kontejneru typu K.
Popsal jsi totéž - pouze z jiného pohledu a mnohem složitěji.
-
Map je kolekcí dvojic (klíč, hodnota).
FlatMap je jednoduchý seznam, ve kterém se střídají klíče a jejich hodnoty.
Tak to vazne neni spravna odpoved v tomhle kontextu.
map vezme nejaky "kontejner" (ve skutecnosti neco obecnejsiho, ale tim se ted netrap), jako je List nebo Maybe, ve kterem jsou prvky typu T a na kazdy prvek aplikuje nejakou fuknci z T na K. Vysledek je ten samy druh kontejneru, ve kterem jsou prvky typu K.
flatMap na ten samy kontejner muze aplikovat funkci, ktera z prvku typu T udela kontejner prvku typu K. A vysledek se slepi opet do kontejneru typu K.
Popsal jsi totéž - pouze z jiného pohledu a mnohem složitěji.
Ne.
map není v tomhle kontextu (pokud nechceš vážně zamotat hlavu tazateli, co očividně začíná) žádná kolekce dvojic, je to funkce vyššího řádu. Podobně u flatmap.
-
Dvě technické: flatMap není monáda, na to nestačí (a chtěl jsem se tomuhle při vysvětlování vyhnout, když se někdo ptá na map vs. flatmap, tak mu to nepomůže.)
Ten příklad, co jsi napsal, nedává úplně smysl. Ta věc u mapu nejde v haskellu napsat a ten výsledek flatmap ti klidně vypadne i z mapu, záleží, co na čím mapuješ.
Jo, s Haskellem mas pravdu, taky jsem se s tim nechtel do detailu parat, a co jsem napsal bylo pro Spark, jestli to nekdo dela distribuovane, kde funkcionalni pristup je zasadni, zatim co Haskell na jednom kompu je vice-mene optional ;-)
-
Popsal jsi totéž - pouze z jiného pohledu a mnohem složitěji.
Ne.
map není v tomhle kontextu (pokud nechceš vážně zamotat hlavu tazateli, co očividně začíná) žádná kolekce dvojic, je to funkce vyššího řádu. Podobně u flatmap.
To zní docela kategoricky. Jako kdyb sis byl svým tvrzením zcela jist.
Nechtěl bys ty své funkce vyššího řádu alespoň popsat srozumitelněji, aby to tazatel pochopil? Ty obrázky vypadají spíš jako můj popis datových struktur.
-
Popsal jsi totéž - pouze z jiného pohledu a mnohem složitěji.
Ne.
map není v tomhle kontextu (pokud nechceš vážně zamotat hlavu tazateli, co očividně začíná) žádná kolekce dvojic, je to funkce vyššího řádu. Podobně u flatmap.
To zní docela kategoricky. Jako kdyb sis byl svým tvrzením zcela jist.
Nechtěl bys ty své funkce vyššího řádu alespoň popsat srozumitelněji, aby to tazatel pochopil? Ty obrázky vypadají spíš jako můj popis datových struktur.
Funkce vyššího řádu je funkce, která jako parametr bere další funkci.
A v těch obrázcích to map a flatmap nejsou ty datové struktury. Map a flatmap jsou transformace jedné datové struktury na jinou. Tazatel explicitně psal o funkcionálním přístupu, takže předpokládám že v případě Javy nemyslel datový typy Map, ale metodu map datového typu Stream.
-
Trochu tápu ve funkcionálním přístupu, jaký je pls rozdíl mezi map a flatMap?
Map je kolekcí dvojic (klíč, hodnota).
FlatMap je jednoduchý seznam, ve kterém se střídají klíče a jejich hodnoty.
Když už ses rozhodnul se v tomhle bahnu rochnit: tu věc, co popisuješ, jako FlatMap vážně někdo používá v jiném kontextu než jako příklad zhůvězilosti?
-
Map je kolekcí dvojic (klíč, hodnota).
FlatMap je jednoduchý seznam, ve kterém se střídají klíče a jejich hodnoty.
Když už ses rozhodnul se v tomhle bahnu rochnit: tu věc, co popisuješ, jako FlatMap vážně někdo používá v jiném kontextu než jako příklad zhůvězilosti?
Posuď sám:
http://martinfowler.com/articles/collection-pipeline/flat-map.html (http://martinfowler.com/articles/collection-pipeline/flat-map.html)
-
No vždyť říkám.
-
No vždyť říkám.
Chceš snad tvrdit, že Martin Fowler píše zhůvěřilosti?
-
Chci tvrdit, že píše o něčem úplně jiném než ty. Což bys pochopil, kdyby jsi ten jeho text přečetl a pochopil.
Flatmap u něj není žádná datová struktura ale úplně normální funkce vyššího řádu.
-
Chci tvrdit, že píše o něčem úplně jiném než ty. Což bys pochopil, kdyby jsi ten jeho text přečetl a pochopil.
Flatmap u něj není žádná datová struktura ale úplně normální funkce vyššího řádu.
... která vytváří datovou strukturu, kterou jsem popsal.
-
Ale houby, podívej se, co se stane, když má nějaký vstupní string lichý počet slov.
-
Zkusim odpovedet trochu srozumitelneji, nez si to tu tradicne zvrhne a nekteri si zacnou nadavat do lopat a podobne.
map a flatMap jsou funkce/procedury vyssiho radu, v tomto pripade ve smyslu, ze jako svuj argument maji proceduru.
Funkce/procedura map dela to, ze vezme kolekci (seznam, stream, apod.) a na kazdy jeji prvek aplikuje predanou proceduru a vrati novou kolekci (seznam, stream).
Stream
.of(1, 2, 3, 4, 5)
.map(x -> x + 1)
.forEach(x -> System.out.println(x));
==> 2, 3, 4, 5, 6
Stream
.of(new int[] {1, 2}, new int[] {3, 4}, new int[] {5, 6, 7})
.map(x -> x.length)
.forEach(x -> System.out.println(x));
==> 2, 2, 3
V prvnim pripade jsou prvky kolekce skalarni hodnoty (cela cisla), v druhem pripade jsou prvky kolekce pole (int[]), ale po kazde pro jednu hodnotu ze vstupni kolekce vytvori pomoci predane procedury prave jednu hodnotu novou.
V pripade flatMap je to slozitejsi, protoze pro kazdou hodnotu ze vstupni kolekce je vytvorena nova kolekce hodnot (ktera muze obsahovat libovolne mnozstvi hodnot, klidne i zadnou) a tyto kolekce jsou pak spojeny v kolekci jednu.
Stream
.of(new int[] {1, 2}, new int[] {3, 4}, new int[] {5, 6, 7})
.flatMapToInt(x -> Arrays.stream(x).map(y -> y + 1))
.forEach(x -> System.out.println(x));
==> 2, 3, 4, 5, 6, 7, 8
Stream
.of(1, 2, 3, 4, 5)
.flatMap(x -> Collections.nCopies(x, x).stream())
.forEach(x -> System.out.println(x));
==> 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5
-
Zkusim odpovedet trochu srozumitelneji, nez si to tu tradicne zvrhne a nekteri si zacnou nadavat do lopat a podobne.
map a flatMap jsou funkce/procedury vyssiho radu, v tomto pripade ve smyslu, ze jako svuj argument maji proceduru.
Funkce/procedura map dela to, ze vezme kolekci (seznam, stream, apod.) a na kazdy jeji prvek aplikuje predanou proceduru a vrati novou kolekci (seznam, stream).
Stream
.of(1, 2, 3, 4, 5)
.map(x -> x + 1)
.forEach(x -> System.out.println(x));
==> 2, 3, 4, 5, 6
Stream
.of(new int[] {1, 2}, new int[] {3, 4}, new int[] {5, 6, 7})
.map(x -> x.length)
.forEach(x -> System.out.println(x));
==> 2, 2, 3
V prvnim pripade jsou prvky kolekce skalarni hodnoty (cela cisla), v druhem pripade jsou prvky kolekce pole (int[]), ale po kazde pro jednu hodnotu ze vstupni kolekce vytvori pomoci predane procedury prave jednu hodnotu novou.
V pripade flatMap je to slozitejsi, protoze pro kazdou hodnotu ze vstupni kolekce je vytvorena nova kolekce hodnot (ktera muze obsahovat libovolne mnozstvi hodnot, klidne i zadnou) a tyto kolekce jsou pak spojeny v kolekci jednu.
Stream
.of(new int[] {1, 2}, new int[] {3, 4}, new int[] {5, 6, 7})
.flatMapToInt(x -> Arrays.stream(x).map(y -> y + 1))
.forEach(x -> System.out.println(x));
==> 2, 3, 4, 5, 6, 7, 8
Stream
.of(1, 2, 3, 4, 5)
.flatMap(x -> Collections.nCopies(x, x).stream())
.forEach(x -> System.out.println(x));
==> 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5
Ještě by asi bylo vhodné dodat, že nemusí jít jen o kolekce, ale že jde o hodně obecný koncept fungující i s Optional, Future apod.
-
Ale houby, podívej se, co se stane, když má nějaký vstupní string lichý počet slov.
Tohle je flattening seznamu seznamů na prostý seznam.
Flattening se však dá udělat i nad slovníkem, resp. i dalšími kolekcemi. Například tato učebnicová funkce v Lispu vytváří z prostého seznamu dvojice klíč=>hodnota.
(defun make-cd (title artist rating ripped)
(list :title title :artist artist :rating rating :ripped ripped))
Podobným způsobem se předávají např. volitelné parametry funkcí.
Flatteningem vznikne seznam se strukturou na druhém řádku, tedy na střídačku klíč a hodnota. Takový seznam se pak dá například vypsat:
(format t "~{~a:~10t~a~%~}~%" cd)
-
Trochu tápu ve funkcionálním přístupu, jaký je pls rozdíl mezi map a flatMap?
Map je kolekcí dvojic (klíč, hodnota).
FlatMap je jednoduchý seznam, ve kterém se střídají klíče a jejich hodnoty.
Když už ses rozhodnul se v tomhle bahnu rochnit: tu věc, co popisuješ, jako FlatMap vážně někdo používá v jiném kontextu než jako příklad zhůvězilosti?
V perlu je => jen alias pro ,.
%a = (1 => 2, 3 => 4)
@b = (1 => 2, 3 => 4)
je stejné co
%a = (1, 2, 3, 4)
@b = (1, 2, 3, 4)
ale nevím jestli se tomu říká flatmap.
Pokud přiřadím hashmapu do pole, dostanu to o čem píše Kit, jen nebude dodrženo pořadí klíčů.
-
Ale houby, podívej se, co se stane, když má nějaký vstupní string lichý počet slov.
Tohle je flattening seznamu seznamů na prostý seznam.
Flattening se však dá udělat i nad slovníkem, resp. i dalšími kolekcemi. Například tato učebnicová funkce v Lispu vytváří z prostého seznamu dvojice klíč=>hodnota.
(defun make-cd (title artist rating ripped)
(list :title title :artist artist :rating rating :ripped ripped))
Podobným způsobem se předávají např. volitelné parametry funkcí.
Flatteningem vznikne seznam se strukturou na druhém řádku, tedy na střídačku klíč a hodnota. Takový seznam se pak dá například vypsat:
(format t "~{~a:~10t~a~%~}~%" cd)
Všimnul sis, že teď už říkáš něco úplně jiného, než byl ten nesmysl na začátku?
-
Všimnul sis, že teď už říkáš něco úplně jiného, než byl ten nesmysl na začátku?
Všiml sis, že hledám společnou řeč?
Flat není funkce, ale přídavné jméno s významem "plochý". FlatMap je doslovně "plochý slovník". Všimni si, že se tazatel ptal na FlatMap, nikoli na flatMap. Ptal se tedy na strukturu, nikoli na funkci, která by se spíš měla jmenovat "flatten", ovšem tento název má již jiná funkce.
-
Ne, nehledáme společnou řeč. Odpovídáme na dotaz - hodně lidí +- správně, ty špatně.
Doufejme, že si to tazatel přebere.
-
Ne, nehledáme společnou řeč. Odpovídáme na dotaz - hodně lidí +- správně, ty špatně.
Jistě jsi chtěl napsat "nehledám společnou řeč".
-
Máš dojem, že faktická odpověď na vcelku jednoznačnou otázku studenta má být o hledání společné řeči mezi odpověďmi a nesmyslem?
-
Všimnul sis, že teď už říkáš něco úplně jiného, než byl ten nesmysl na začátku?
Všiml sis, že hledám společnou řeč?
Flat není funkce, ale přídavné jméno s významem "plochý". FlatMap je doslovně "plochý slovník". Všimni si, že se tazatel ptal na FlatMap, nikoli na flatMap. Ptal se tedy na strukturu, nikoli na funkci, která by se spíš měla jmenovat "flatten", ovšem tento název má již jiná funkce.
jste to vy, Miloši?
-
Všimni si, že se tazatel ptal na FlatMap, nikoli na flatMap.
Vazne?
Otazka znela:
Trochu tápu ve funkcionálním přístupu, jaký je pls rozdíl mezi map a flatMap?
-
Všimni si, že se tazatel ptal na FlatMap, nikoli na flatMap.
Vazne?
Otazka znela:
Trochu tápu ve funkcionálním přístupu, jaký je pls rozdíl mezi map a flatMap?
Podívej se do nadpisu vlákna.
-
Všimni si, že se tazatel ptal na FlatMap, nikoli na flatMap.
Vazne?
Otazka znela:
Trochu tápu ve funkcionálním přístupu, jaký je pls rozdíl mezi map a flatMap?
Podívej se do nadpisu vlákna.
otázka není v nadpisu, ale v textu příspěvku a autorem nadpisu bývá často moderátor, nevěřím, že jste si toho ještě nevšiml
-
otázka není v nadpisu, ale v textu příspěvku a autorem nadpisu bývá často moderátor, nevěřím, že jste si toho ještě nevšiml
Nevšiml jsem si ani, že bys tazateli jakkoli odpověděl na otázku. Zřejmě máš obavu, že tvá odpověď bude také označena jako chybná.
-
otázka není v nadpisu, ale v textu příspěvku a autorem nadpisu bývá často moderátor, nevěřím, že jste si toho ještě nevšiml
Nevšiml jsem si ani, že bys tazateli jakkoli odpověděl na otázku. Zřejmě máš obavu, že tvá odpověď bude také označena jako chybná.
myslím, že otázka byla zodpovězěna, zároveň mi přijde vhodné poukázat, že některé odpovědi byly nesmyslné (mohou totiž tazatele zmást), a tedy naznačit autorovi oné nesmyslné odpovědi, že by měl napsat něco jako "pardon, spletl jsem se" aby tazatel jeho odpověď nepovažoval za relevantní je ku prospěchu věci
-
otázka není v nadpisu, ale v textu příspěvku a autorem nadpisu bývá často moderátor, nevěřím, že jste si toho ještě nevšiml
Nevšiml jsem si ani, že bys tazateli jakkoli odpověděl na otázku. Zřejmě máš obavu, že tvá odpověď bude také označena jako chybná.
myslím, že otázka byla zodpovězěna, zároveň mi přijde vhodné poukázat, že některé odpovědi byly nesmyslné (mohou totiž tazatele zmást), a tedy naznačit autorovi oné nesmyslné odpovědi, že by měl napsat něco jako "pardon, spletl jsem se" aby tazatel jeho odpověď nepovažoval za relevantní je ku prospěchu věci
Tak mu to naznač.
-
(facepalm s výkrutem)
-
(facepalm s výkrutem)
Nemusíš se tady fackovat. Ostatní ti tu službu určitě rádi udělají.
-
Když už tu píšeš chybné odpovědi, tak alespoň nedržkuj.
-
Když už tu píšeš chybné odpovědi, tak alespoň nedržkuj.
Stejně to nefunguje:
(facepalm s výkrutem)
*** - EVAL: undefined function FACEPALM
-
Nerad tě na to upozorňuji, ale zodpovídáš jenom otázku "umí se Kit chovat jako trolící nevychované hovado?", ne to, na co se tazatel ptal.
-
Nerad tě na to upozorňuji, ale zodpovídáš jenom otázku "umí se Kit chovat jako trolící nevychované hovado?", ne to, na co se tazatel ptal.
Mezi námi je ten rozdíl, že se tě nepokouším urazit. Tak mě přestaň trolit.
-
Rozdíl je v tom, že ty tu na rozdíl od všech ostatních dáváš špatnou odpověď a pak ještě prudíš.
-
Rozdíl je v tom, že ty tu na rozdíl od všech ostatních dáváš špatnou odpověď a pak ještě prudíš.
Ukazuji jiný úhel pohledu, než ostatní. A to rozhodně není špatně.
A já jsem si s fackováním nezačal, takže se laskavě nejdřív podívej do zrcadla.
-
Neschovávej špatnou odpověď za jiný úhel pohledu. Tohle není rozbor poezie.
-
Neschovávej špatnou odpověď za jiný úhel pohledu. Tohle není rozbor poezie.
Ani ses nenamáhal mi dokázat, že má odpověď je špatná. Pouhé tvé tvrzení.
-
http://lmgtfy.com/?q=flatmap+data+structure
http://lmgtfy.com/?q=flatmap+represented+in+list
Ale ono dost neznačí i to, když dáváš na podporu svého tvrzení link na stránky, které ukazují opak...
-
http://lmgtfy.com/?q=flatmap+data+structure
http://lmgtfy.com/?q=flatmap+represented+in+list
Ale ono dost neznačí i to, když dáváš na podporu svého tvrzení link na stránky, které ukazují opak...
Na uvedených odkazech pracují pouze seznamy seznamů. To je málo.
-
https://xkcd.com/386/
-
http://lmgtfy.com/?q=flatmap+data+structure
http://lmgtfy.com/?q=flatmap+represented+in+list
Ale ono dost neznačí i to, když dáváš na podporu svého tvrzení link na stránky, které ukazují opak...
Na uvedených odkazech pracují pouze seznamy seznamů. To je málo.
Tak pošli odkaz na nějaký jiný solidní zdroj. Tentokrát zkus takový, který říká, co ty. Ne opak.
-
https://xkcd.com/386/
Přesně tak ;)
-
Na uvedených odkazech pracují pouze seznamy seznamů. To je málo.
Tak pošli odkaz na nějaký jiný solidní zdroj. Tentokrát zkus takový, který říká, co ty. Ne opak.
Tak ještě jednou:
http://martinfowler.com/articles/collection-pipeline/flat-map.html (http://martinfowler.com/articles/collection-pipeline/flat-map.html)
Map a function over a collection and flatten the result by one-level
-
Ještě by asi bylo vhodné dodat, že nemusí jít jen o kolekce, ale že jde o hodně obecný koncept fungující i s Optional, Future apod.
Na vstupu nebo na výstupu? Já mám teda flatMap zafixováno tak, že vrací vždy kolekci. V ostatních případech se používají funkce s jiným jménem.
-
Ještě by asi bylo vhodné dodat, že nemusí jít jen o kolekce, ale že jde o hodně obecný koncept fungující i s Optional, Future apod.
Na vstupu nebo na výstupu? Já mám teda flatMap zafixováno tak, že vrací vždy kolekci. V ostatních případech se používají funkce s jiným jménem.
FlatMap je join.map a definuje se tak, aby splňovalo monadické zákony. Někdy se mu taky říká bind, ale až na terminologii je to obecný koncept vracející monadickou hodnotu a kolekce jsou jen jedna velmi specifická oblast použití.
-
Na uvedených odkazech pracují pouze seznamy seznamů. To je málo.
Tak pošli odkaz na nějaký jiný solidní zdroj. Tentokrát zkus takový, který říká, co ty. Ne opak.
Tak ještě jednou:
http://martinfowler.com/articles/collection-pipeline/flat-map.html (http://martinfowler.com/articles/collection-pipeline/flat-map.html)
Map a function over a collection and flatten the result by one-level
Tak ještě jednou: Fowler píše, že je flatmap operace vyššího řádu, ne ta zhůvězilá datová struktura, co jsi popsal:
FlatMap je jednoduchý seznam, ve kterém se střídají klíče a jejich hodnoty.
-
Ještě by asi bylo vhodné dodat, že nemusí jít jen o kolekce, ale že jde o hodně obecný koncept fungující i s Optional, Future apod.
Na vstupu nebo na výstupu? Já mám teda flatMap zafixováno tak, že vrací vždy kolekci. V ostatních případech se používají funkce s jiným jménem.
Třebas v Javě je to otázka Streamu a ty nemusíš mít navázané jenom na kolekce, v Haskellu stačí functor, ve Scale GenTraversableOnce, v RX bývají nějaké ty Observables...
-
Ještě by asi bylo vhodné dodat, že nemusí jít jen o kolekce, ale že jde o hodně obecný koncept fungující i s Optional, Future apod.
Na vstupu nebo na výstupu? Já mám teda flatMap zafixováno tak, že vrací vždy kolekci. V ostatních případech se používají funkce s jiným jménem.
Třebas v Javě je to otázka Streamu a ty nemusíš mít navázané jenom na kolekce, v Haskellu stačí functor, ve Scale GenTraversableOnce, v RX bývají nějaké ty Observables...
Záleží, v jakém kontextu se o flatMap mluví.
Dá se vnímat úžeji, jako operace na kolekcích spojující map+flatten. Takhle to budou chápat třeba Rubyisti (http://apidock.com/ruby/Enumerable/flat_map).
Nebo se dá vnímat šířeji, jako monadická operace bind (v haskellu >>=). Takhle to budou chápat třeba Scalisti.
Je asi vhodné se před diskuzí domluvit, který význam se bude používat, nebo si alespoň uvědomit, že možné a správné jsou oba, záleží na společnosti.
Jinak V Haskellu je třeba alespoň Monad. Functor má pouze map.
Ve scale jsou traversables jen jedna z věcí co flatMap umí, další jsou třeba to zmiňované Future, Option atp. For comprehension principiálně funguje na každé třídě, která má definována flatMap, (+map, filter/withFilter).
V Rx prakticky nic jiného než Observable není, a ano, umí flatMap :)
-
@ava
S tím functorem máš pochopitelně pravdu, měl bych přestat psát na interweby před prvním kafem :-/
-
Ještě by asi bylo vhodné dodat, že nemusí jít jen o kolekce, ale že jde o hodně obecný koncept fungující i s Optional, Future apod.
Na vstupu nebo na výstupu? Já mám teda flatMap zafixováno tak, že vrací vždy kolekci. V ostatních případech se používají funkce s jiným jménem.
Abych to ještě upřesnil a ukázal na příkladu, pokud mám např. seznam [1,2,nil,3] typu [Int?] a chci odfiltrovat nil (a dostat [Int]), použiju metodu "map" Optionalu:
list.flatMap{$0.map{[$0]} ?? []}
Nenulové prvky se "vytáhnou" z Optional a udělá se z nich singleton, zatímco nil se převede na prázdný seznam, z čehož pak flatMap zase udělá seznam (joinem).
-
Ještě by asi bylo vhodné dodat, že nemusí jít jen o kolekce, ale že jde o hodně obecný koncept fungující i s Optional, Future apod.
Na vstupu nebo na výstupu? Já mám teda flatMap zafixováno tak, že vrací vždy kolekci. V ostatních případech se používají funkce s jiným jménem.
Abych to ještě upřesnil a ukázal na příkladu, pokud mám např. seznam [1,2,nil,3] typu [Int?] a chci odfiltrovat nil (a dostat [Int]), použiju metodu "map" Optionalu:
list.flatMap{$0.map{[$0]} ?? []}
Nenulové prvky se "vytáhnou" z Optional a udělá se z nich singleton, zatímco nil se převede na prázdný seznam, z čehož pak flatMap zase udělá seznam (joinem).
Neříkám, že ten tvůj způsob postrádá eleganci... Ale přijde mi, že jen využíváš chování flatMap, než, že by to na toto bylo určeno.
Já bych to třeba napsal takto:
map fromJust $ filter isJust seznam
Je to humpolácké, a mechanické, uznávám :-)
Každopádně, mám naučené spíše takové využití, kdy mám pole funkcí vracející pole. A nechci pole polí, ale, protože mi nezáleží na indexu, ale jen existenci, tak jen jednoúrovňové pole. Nebo když mám strom, a chci v něm najít výskyt nějakých prvků.
Takže mě oprav, na vstupu může být cokoliv, na výstupu je kolekce/pole. Nebo může být na výstupu i Future?
-
Ještě by asi bylo vhodné dodat, že nemusí jít jen o kolekce, ale že jde o hodně obecný koncept fungující i s Optional, Future apod.
Na vstupu nebo na výstupu? Já mám teda flatMap zafixováno tak, že vrací vždy kolekci. V ostatních případech se používají funkce s jiným jménem.
Abych to ještě upřesnil a ukázal na příkladu, pokud mám např. seznam [1,2,nil,3] typu [Int?] a chci odfiltrovat nil (a dostat [Int]), použiju metodu "map" Optionalu:
list.flatMap{$0.map{[$0]} ?? []}
Nenulové prvky se "vytáhnou" z Optional a udělá se z nich singleton, zatímco nil se převede na prázdný seznam, z čehož pak flatMap zase udělá seznam (joinem).
Neříkám, že ten tvůj způsob postrádá eleganci... Ale přijde mi, že jen využíváš chování flatMap, než, že by to na toto bylo určeno.
Já bych to třeba napsal takto:
map fromJust $ filter isJust seznam
Je to humpolácké, a mechanické, uznávám :-)
Každopádně, mám naučené spíše takové využití, kdy mám pole funkcí vracející pole. A nechci pole polí, ale, protože mi nezáleží na indexu, ale jen existenci, tak jen jednoúrovňové pole. Nebo když mám strom, a chci v něm najít výskyt nějakých prvků.
Takže mě oprav, na vstupu může být cokoliv, na výstupu je kolekce/pole. Nebo může být na výstupu i Future?
Jistě, na výstupu může cokoliv komplexního (přesněji jakýkoliv komplexní typ splňující monadické zákony), takže třeba Future nebo Optional, u Optional pak typ funkce bude T->T?. Nebo když to bude Future, dá se pak volání více funkcí pomocí flatMap zřetězit. Akorát by pak asi bylo lepší pojmenovat funkci "joinMap", ale to je jen terminologie, ostatně v Haskellu se tomu říká "bind" (což dává smysl pro různé typy kolekcí, kontejnerů apod.) a konvencí pro tuto operaci je >>=.
-
Jistě, na výstupu může cokoliv komplexního (přesněji jakýkoliv komplexní typ splňující monadické zákony), takže třeba Future nebo Optional, u Optional pak typ funkce bude T->T?. Nebo když to bude Future, dá se pak volání více funkcí pomocí flatMap zřetězit. Akorát by pak asi bylo lepší pojmenovat funkci "joinMap", ale to je jen terminologie, ostatně v Haskellu se tomu říká "bind" (což dává smysl pro různé typy kolekcí, kontejnerů apod.) a konvencí pro tuto operaci je >>=.
to se mi nějak nezdá, jak se pomocí monadického rozhraní poskládá (např.) seznam?
-
to se mi nějak nezdá, jak se pomocí monadického rozhraní poskládá (např.) seznam?
Pokud jsem pochopil otazku, tak by mohlo vysvetlit tohle:
https://en.wikibooks.org/wiki/Haskell/Understanding_monads/List
-
to se mi nějak nezdá, jak se pomocí monadického rozhraní poskládá (např.) seznam?
Pokud jsem pochopil otazku, tak by mohlo vysvetlit tohle:
https://en.wikibooks.org/wiki/Haskell/Understanding_monads/List
možná tam je, ale já ji nevidim, možná jsem se v tom trošku ztratil
otázka by mohla být jak pomocí (>>=) a return (když už teda chcete haskell) udělám z [1] a [2] hodnotu [1,2]
-
možná tam je, ale já ji nevidim, možná jsem se v tom trošku ztratil
otázka by mohla být jak pomocí (>>=) a return (když už teda chcete haskell) udělám z [1] a [2] hodnotu [1,2]
Možná jestli to nebude podobné, jako ten detail, že v Haskellu je [1, 2, 3]
ve skutečnosti 1:2:3:[]
-
možná tam je, ale já ji nevidim, možná jsem se v tom trošku ztratil
otázka by mohla být jak pomocí (>>=) a return (když už teda chcete haskell) udělám z [1] a [2] hodnotu [1,2]
Možná jestli to nebude podobné, jako ten detail, že v Haskellu je [1, 2, 3]
ve skutečnosti 1:2:3:[]
nerozumím
-
možná tam je, ale já ji nevidim, možná jsem se v tom trošku ztratil
otázka by mohla být jak pomocí (>>=) a return (když už teda chcete haskell) udělám z [1] a [2] hodnotu [1,2]
Možná jestli to nebude podobné, jako ten detail, že v Haskellu je [1, 2, 3]
ve skutečnosti 1:2:3:[]
Na konkrétní implementaci nijak nezáleží. Streamy (např. v Javě) fungují podobně. V případě [1] a [2] stačí udělat jen "join" (aka "flatten") (což není přímá odpověď na otázku, jak to udělat pomocí >>=, ale "join" je jen x>>=id, kde id je identické zobrazení).
-
možná tam je, ale já ji nevidim, možná jsem se v tom trošku ztratil
otázka by mohla být jak pomocí (>>=) a return (když už teda chcete haskell) udělám z [1] a [2] hodnotu [1,2]
Možná jestli to nebude podobné, jako ten detail, že v Haskellu je [1, 2, 3]
ve skutečnosti 1:2:3:[]
Na konkrétní implementaci nijak nezáleží. Streamy (např. v Javě) fungují podobně. V případě [1] a [2] stačí udělat jen "join" (aka "flatten") (což není přímá odpověď na otázku, jak to udělat pomocí >>=, ale "join" je jen x>>=id, kde id je identické zobrazení).
no a jak se to teda udělá?
-
možná tam je, ale já ji nevidim, možná jsem se v tom trošku ztratil
otázka by mohla být jak pomocí (>>=) a return (když už teda chcete haskell) udělám z [1] a [2] hodnotu [1,2]
Možná jestli to nebude podobné, jako ten detail, že v Haskellu je [1, 2, 3]
ve skutečnosti 1:2:3:[]
Na konkrétní implementaci nijak nezáleží. Streamy (např. v Javě) fungují podobně. V případě [1] a [2] stačí udělat jen "join" (aka "flatten") (což není přímá odpověď na otázku, jak to udělat pomocí >>=, ale "join" je jen x>>=id, kde id je identické zobrazení).
no a jak se to teda udělá?
Ve Swiftu:
[[1],[2]].flatMap{$0}
-
Ve Swiftu:
[[1],[2]].flatMap{$0}
swift neznám, ale řekl bych, že ekvivalentní kód v haskellu by byl join [[1], [2]] - jenže to není odpověď na mou otázku
-
Ve Swiftu:
[[1],[2]].flatMap{$0}
swift neznám, ale řekl bych, že ekvivalentní kód v haskellu by byl join [[1], [2]] - jenže to není odpověď na mou otázku
V tom případě doporučuju tu otázku přeformulovat, evidentně jsem ji špatně pochopil. BTW ekvivalentní není, to by bylo [[1],[2]].flatten()
-
Ve Swiftu:
[[1],[2]].flatMap{$0}
swift neznám, ale řekl bych, že ekvivalentní kód v haskellu by byl join [[1], [2]] - jenže to není odpověď na mou otázku
V tom případě doporučuju tu otázku přeformulovat, evidentně jsem ji špatně pochopil. BTW ekvivalentní není, to by bylo [[1],[2]].flatten()
pomocí syntaxe haskellu:
implementace funkce f
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
-
Ve Swiftu:
[[1],[2]].flatMap{$0}
swift neznám, ale řekl bych, že ekvivalentní kód v haskellu by byl join [[1], [2]] - jenže to není odpověď na mou otázku
V tom případě doporučuju tu otázku přeformulovat, evidentně jsem ji špatně pochopil. BTW ekvivalentní není, to by bylo [[1],[2]].flatten()
pomocí syntaxe haskellu:
implementace funkce f
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
f(x,y)=join([x,y])
nebo jen pomocí flatMap
f(x,y)=[x,y]>>=id
-
Ve Swiftu:
[[1],[2]].flatMap{$0}
swift neznám, ale řekl bych, že ekvivalentní kód v haskellu by byl join [[1], [2]] - jenže to není odpověď na mou otázku
V tom případě doporučuju tu otázku přeformulovat, evidentně jsem ji špatně pochopil. BTW ekvivalentní není, to by bylo [[1],[2]].flatten()
pomocí syntaxe haskellu:
implementace funkce f
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
f(x,y)=join([x,y])
nebo jen pomocí flatMap
f(x,y)=[x,y]>>=id
to ovšem neodpovídá datovému typu, který jsem uvedl, v haskellu je takový kód použitelný pouze pro "List monádu"
-
Ve Swiftu:
[[1],[2]].flatMap{$0}
swift neznám, ale řekl bych, že ekvivalentní kód v haskellu by byl join [[1], [2]] - jenže to není odpověď na mou otázku
V tom případě doporučuju tu otázku přeformulovat, evidentně jsem ji špatně pochopil. BTW ekvivalentní není, to by bylo [[1],[2]].flatten()
pomocí syntaxe haskellu:
implementace funkce f
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
f(x,y)=join([x,y])
nebo jen pomocí flatMap
f(x,y)=[x,y]>>=id
to ovšem neodpovídá datovému typu, který jsem uvedl, v haskellu je takový kód použitelný pouze pro "List monádu"
A co má ta funkce jako obecně dělat? Monády se specifikují jen pomocí unit, join a map, z čehož se dá flatMap vždy odvodit. Konkatenace není obecně definovatelná.
-
Monády se specifikují jen pomocí unit, join a map, z čehož se dá flatMap vždy odvodit. Konkatenace není obecně definovatelná.
původně jsem reagoval na tohle:
Takže mě oprav, na vstupu může být cokoliv, na výstupu je kolekce/pole. Nebo může být na výstupu i Future?
Jistě, na výstupu může cokoliv komplexního (přesněji jakýkoliv komplexní typ splňující monadické zákony)
plyne mi z toho, že je možné sadu monadických hodnot slepit dohromady jenom pomocí "rozhraní" monády/funktoru (>>=,return, fmap), taky aby šlo napsat něco jako moje_flatMap (\i->) [1,2] == [1,2], kde typ výsledku funkce je prostě Monad m => m a - a to se mi nezdá (s přihlédnutím k situaci v knihovnách haskellu, kde se u podobné funkce na výstupu vyskytuje monoid)
-
Ve Swiftu:
[[1],[2]].flatMap{$0}
swift neznám, ale řekl bych, že ekvivalentní kód v haskellu by byl join [[1], [2]] - jenže to není odpověď na mou otázku
V tom případě doporučuju tu otázku přeformulovat, evidentně jsem ji špatně pochopil. BTW ekvivalentní není, to by bylo [[1],[2]].flatten()
pomocí syntaxe haskellu:
implementace funkce f
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
f(x,y)=join([x,y])
nebo jen pomocí flatMap
f(x,y)=[x,y]>>=id
to ovšem neodpovídá datovému typu, který jsem uvedl, v haskellu je takový kód použitelný pouze pro "List monádu"
No podle mě to přesně odpovídá datovému typu, který jsi uvedl. Chceš, aby výsledek byl [1,2], tedy aby to byl List, a tím už jsi řekl, na jaké monádě má f pracovat - na Listu (vlastně jsi zafixoval to poslední m z 'f :: Monad m => m a -> m a -> m a', ale tím jsi přeci zafixoval všechna m.)
-
No podle mě to přesně odpovídá datovému typu, který jsi uvedl. Chceš, aby výsledek byl [1,2], tedy aby to byl List, a tím už jsi řekl, na jaké monádě má f pracovat - na Listu (vlastně jsi zafixoval to poslední m z 'f :: Monad m => m a -> m a -> m a', ale tím jsi přeci zafixoval všechna m.)
ty uvedené funkce nemůžou mít datový typ jaký jsem uvedl, pracují přímo s Listem, ale já se ptám na obecnou monádu, funkce, která je definovaná pro všechny monády může pracovat i s Listem, ale funkce definovaná pro List nemůže pracovat s každou monádou
-
@v Sorry ale nerozumím. Můžeš prosím znovu co nejsrozumitelněji naformulovat celou otázku v jednom příspěvku bez odkazů na předchozí příspěvky, ať se vyhrabeme z toho zmatku? Díky..
-
@v Sorry ale nerozumím. Můžeš prosím znovu co nejsrozumitelněji naformulovat celou otázku v jednom příspěvku bez odkazů na předchozí příspěvky, ať se vyhrabeme z toho zmatku? Díky..
to nevím jestli umím :D
IMHO vrcholu srozumitelnosti jsem dosáhl, když jsem se zeptal jestli je možné implementovat tuto funkci:
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
motivace pro tento dotaz je příspěvěk zboj 27. 09. 2016, 15:24:02
(implementace f a b = join [a, b] neodpovídá zadanému datovému typu)
-
@v Sorry ale nerozumím. Můžeš prosím znovu co nejsrozumitelněji naformulovat celou otázku v jednom příspěvku bez odkazů na předchozí příspěvky, ať se vyhrabeme z toho zmatku? Díky..
to nevím jestli umím :D
IMHO vrcholu srozumitelnosti jsem dosáhl, když jsem se zeptal jestli je možné implementovat tuto funkci:
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
motivace pro tento dotaz je příspěvěk zboj 27. 09. 2016, 15:24:02
(implementace f a b = join [a, b] neodpovídá zadanému datovému typu)
OK, diky, uz rozumim, rozumim i jak jsi myslel to ze f a b = join [a, b] neodpovida datovemu typu - je to naopak nez jsem psal nahore - [] nelze v implementaci pouzit, tim bych tvrdil ze Monad musi byt List monad, coz nechci.
Zajimava otazka, aspon mam nad cim premyslet, jsem v tomhle oboru zacatecnik, tak se aspon procvicim :)
-
@v Sorry ale nerozumím. Můžeš prosím znovu co nejsrozumitelněji naformulovat celou otázku v jednom příspěvku bez odkazů na předchozí příspěvky, ať se vyhrabeme z toho zmatku? Díky..
to nevím jestli umím :D
IMHO vrcholu srozumitelnosti jsem dosáhl, když jsem se zeptal jestli je možné implementovat tuto funkci:
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
motivace pro tento dotaz je příspěvěk zboj 27. 09. 2016, 15:24:02
(implementace f a b = join [a, b] neodpovídá zadanému datovému typu)
Hmm, řekl bych že to nejde. U listu to vypadá v pohodě, ale jak by vůbec měl vypadat očekávaný výsledek třeba na Maybe?
f (Just 1) (Just 2) = ??
Pravda, není to moc rigorózní úvaha, ale intuitivně se mi zdá, že f tak jak ho chceš naimplementovat nejde.
-
@v Sorry ale nerozumím. Můžeš prosím znovu co nejsrozumitelněji naformulovat celou otázku v jednom příspěvku bez odkazů na předchozí příspěvky, ať se vyhrabeme z toho zmatku? Díky..
to nevím jestli umím :D
IMHO vrcholu srozumitelnosti jsem dosáhl, když jsem se zeptal jestli je možné implementovat tuto funkci:
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
motivace pro tento dotaz je příspěvěk zboj 27. 09. 2016, 15:24:02
(implementace f a b = join [a, b] neodpovídá zadanému datovému typu)
Hmm, řekl bych že to nejde. U listu to vypadá v pohodě, ale jak by vůbec měl vypadat očekávaný výsledek třeba na Maybe?
f (Just 1) (Just 2) = ??
Pravda, není to moc rigorózní úvaha, ale intuitivně se mi zdá, že f tak jak ho chceš naimplementovat nejde.
ohledně Maybe, pro inspiraci bych se podíval na Data.Monoid
já nevím jestli to jde, ale objevila se tady myšlenka, že výstupní typ flatMap má být monáda a to stačí, to je v rozporu s mou představou o flatMap i s tím co (si myslím že) vím o monádách, no a tak se ptám
-
@v Sorry ale nerozumím. Můžeš prosím znovu co nejsrozumitelněji naformulovat celou otázku v jednom příspěvku bez odkazů na předchozí příspěvky, ať se vyhrabeme z toho zmatku? Díky..
to nevím jestli umím :D
IMHO vrcholu srozumitelnosti jsem dosáhl, když jsem se zeptal jestli je možné implementovat tuto funkci:
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
motivace pro tento dotaz je příspěvěk zboj 27. 09. 2016, 15:24:02
(implementace f a b = join [a, b] neodpovídá zadanému datovému typu)
Hmm, řekl bych že to nejde. U listu to vypadá v pohodě, ale jak by vůbec měl vypadat očekávaný výsledek třeba na Maybe?
f (Just 1) (Just 2) = ??
Pravda, není to moc rigorózní úvaha, ale intuitivně se mi zdá, že f tak jak ho chceš naimplementovat nejde.
Aby to dávalo smysl, monáda musí být aditivní, pak stačí funkci definovat jako x++y. Tím jsme ale dost odbočili od flatMap.
-
@v Sorry ale nerozumím. Můžeš prosím znovu co nejsrozumitelněji naformulovat celou otázku v jednom příspěvku bez odkazů na předchozí příspěvky, ať se vyhrabeme z toho zmatku? Díky..
to nevím jestli umím :D
IMHO vrcholu srozumitelnosti jsem dosáhl, když jsem se zeptal jestli je možné implementovat tuto funkci:
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
motivace pro tento dotaz je příspěvěk zboj 27. 09. 2016, 15:24:02
(implementace f a b = join [a, b] neodpovídá zadanému datovému typu)
Hmm, řekl bych že to nejde. U listu to vypadá v pohodě, ale jak by vůbec měl vypadat očekávaný výsledek třeba na Maybe?
f (Just 1) (Just 2) = ??
Pravda, není to moc rigorózní úvaha, ale intuitivně se mi zdá, že f tak jak ho chceš naimplementovat nejde.
ohledně Maybe, pro inspiraci bych se podíval na Data.Monoid
já nevím jestli to jde, ale objevila se tady myšlenka, že výstupní typ flatMap má být monáda a to stačí, to je v rozporu s mou představou o flatMap i s tím co (si myslím že) vím o monádách, no a tak se ptám
flatMap má typ ma->(a->mb)->mb. Kde přesně je ten rozpor?
-
flatMap má typ ma->(a->ma)->ma. Kde přesně je ten rozpor?
já si představuju typ t a -> (a -> m b) -> m b, jednak jste mluvil o monádě na výstupu, což IMHO znamená, že na vstupu je něco jiného, druhak Data.Foldable.foldMap (se jeví takový pohodlnější) a za třetí ten váš flatMap je dost omezený co se týče mapování samotného (a -> a), ale to je asi překlep
-
@v Sorry ale nerozumím. Můžeš prosím znovu co nejsrozumitelněji naformulovat celou otázku v jednom příspěvku bez odkazů na předchozí příspěvky, ať se vyhrabeme z toho zmatku? Díky..
to nevím jestli umím :D
IMHO vrcholu srozumitelnosti jsem dosáhl, když jsem se zeptal jestli je možné implementovat tuto funkci:
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
motivace pro tento dotaz je příspěvěk zboj 27. 09. 2016, 15:24:02
(implementace f a b = join [a, b] neodpovídá zadanému datovému typu)
Hmm, řekl bych že to nejde. U listu to vypadá v pohodě, ale jak by vůbec měl vypadat očekávaný výsledek třeba na Maybe?
f (Just 1) (Just 2) = ??
Pravda, není to moc rigorózní úvaha, ale intuitivně se mi zdá, že f tak jak ho chceš naimplementovat nejde.
Aby to dávalo smysl, monáda musí být aditivní, pak stačí funkci definovat jako x++y. Tím jsme ale dost odbočili od flatMap.
Nojo, tak to je ale trochu podvod :) Ale interpretuju to tak, že na Monad f implementovat nejde, na MonadPlus jo.
-
flatMap má typ ma->(a->ma)->ma. Kde přesně je ten rozpor?
já si představuju typ t a -> (a -> m b) -> m b, jednak jste mluvil o monádě na výstupu, což IMHO znamená, že na vstupu je něco jiného, druhak Data.Foldable.foldMap (se jeví takový pohodlnější) a za třetí ten váš flatMap je dost omezený co se týče mapování samotného (a -> a), ale to je asi překlep
Ten typ, co jsem napsal, je *definice* flatMap. Join, unit a flatMap jsou přesně definované a navzájem provázané a není možné jejich typy měnit. Samozřejmě se dá vymyslet nějaká jiná užitečná funkce nad monádami, ale pak by se neměla jmenovat flatMap, protože to je pevně daný koncept, stejně jako si nemůžu říct, že "celé číslo" pro mě od teď budou všechna racionální čísla větší než π (teda říct si to můžu, ale pak se s nikým nedomluvím).
-
@v Sorry ale nerozumím. Můžeš prosím znovu co nejsrozumitelněji naformulovat celou otázku v jednom příspěvku bez odkazů na předchozí příspěvky, ať se vyhrabeme z toho zmatku? Díky..
to nevím jestli umím :D
IMHO vrcholu srozumitelnosti jsem dosáhl, když jsem se zeptal jestli je možné implementovat tuto funkci:
f :: Monad m => m a -> m a -> m a
tak aby f [1] [2] == [1,2]
motivace pro tento dotaz je příspěvěk zboj 27. 09. 2016, 15:24:02
(implementace f a b = join [a, b] neodpovídá zadanému datovému typu)
Hmm, řekl bych že to nejde. U listu to vypadá v pohodě, ale jak by vůbec měl vypadat očekávaný výsledek třeba na Maybe?
f (Just 1) (Just 2) = ??
Pravda, není to moc rigorózní úvaha, ale intuitivně se mi zdá, že f tak jak ho chceš naimplementovat nejde.
Aby to dávalo smysl, monáda musí být aditivní, pak stačí funkci definovat jako x++y. Tím jsme ale dost odbočili od flatMap.
Nojo, tak to je ale trochu podvod :) Ale interpretuju to tak, že na Monad f implementovat nejde, na MonadPlus jo.
Jistě, bez nějaké dodatečné struktury konkatenace smysluplně definovat nejde. Taky jsem nikdy netvrdil, že něco takového je možné a popravdě moc ani smysl té původní otázky nechápu. Vzhledem k nedávnému vývoji této diskuze asi nedorozumění způsobil zmatek ohledně typu flatMap (viz výše).
-
flatMap má typ ma->(a->ma)->ma. Kde přesně je ten rozpor?
já si představuju typ t a -> (a -> m b) -> m b, jednak jste mluvil o monádě na výstupu, což IMHO znamená, že na vstupu je něco jiného, druhak Data.Foldable.foldMap (se jeví takový pohodlnější) a za třetí ten váš flatMap je dost omezený co se týče mapování samotného (a -> a), ale to je asi překlep
Ten typ, co jsem napsal, je *definice* flatMap. Join, unit a flatMap jsou přesně definované a navzájem provázané a není možné jejich typy měnit. Samozřejmě se dá vymyslet nějaká jiná užitečná funkce nad monádami, ale pak by se neměla jmenovat flatMap, protože to je pevně daný koncept, stejně jako si nemůžu říct, že "celé číslo" pro mě od teď budou všechna racionální čísla větší než π (teda říct si to můžu, ale pak se s nikým nedomluvím).
pak tedy je problém čistě ve formulaci "na výstupu"
-
flatMap má typ ma->(a->ma)->ma. Kde přesně je ten rozpor?
já si představuju typ t a -> (a -> m b) -> m b, jednak jste mluvil o monádě na výstupu, což IMHO znamená, že na vstupu je něco jiného, druhak Data.Foldable.foldMap (se jeví takový pohodlnější) a za třetí ten váš flatMap je dost omezený co se týče mapování samotného (a -> a), ale to je asi překlep
Ten typ, co jsem napsal, je *definice* flatMap. Join, unit a flatMap jsou přesně definované a navzájem provázané a není možné jejich typy měnit. Samozřejmě se dá vymyslet nějaká jiná užitečná funkce nad monádami, ale pak by se neměla jmenovat flatMap, protože to je pevně daný koncept, stejně jako si nemůžu říct, že "celé číslo" pro mě od teď budou všechna racionální čísla větší než π (teda říct si to můžu, ale pak se s nikým nedomluvím).
pak tedy je problém čistě ve formulaci "na výstupu"
Výstupním typem je libovolná, ale stejná monáda (např. List, Future nebo Continuation), základový typ může být jiný (jakýkoliv).
-
to se mi nějak nezdá, jak se pomocí monadického rozhraní poskládá (např.) seznam?
Pokud jsem pochopil otazku, tak by mohlo vysvetlit tohle:
https://en.wikibooks.org/wiki/Haskell/Understanding_monads/List
možná tam je, ale já ji nevidim, možná jsem se v tom trošku ztratil
otázka by mohla být jak pomocí (>>=) a return (když už teda chcete haskell) udělám z [1] a [2] hodnotu [1,2]
Myslím, že zboj myslel spíš to, že pomocí bindu můžu hezky "simulovat" map i flatMap:
map:
Prelude> [1,2,3] >>= (\x -> [x*2])
[2,4,6]
flatMap:
Prelude> [1,2,3] >>= (\x -> [x,x])
[1,1,2,2,3,3]
filter:
Prelude> [1,2,3] >>= (\x -> if x==1 then [] else [x])
[2,3]
...ale ne naopak, čili bind je "silnější"/"obecnější" koncept.
Samozřejmě to neznamená, že by si nějaká obecná fce nad monádami vycucala z prstu, že když dostane dva listy, tak je má zřetězit, to jí samozřejmě musím nějak říct, že má udělat zrovna toto :)
-
Samozřejmě to neznamená, že by si nějaká obecná fce nad monádami vycucala z prstu, že když dostane dva listy, tak je má zřetězit, to jí samozřejmě musím nějak říct, že má udělat zrovna toto :)
Ještě dodatek k tomuhle: myslím, že není od věci si uvědomit, že "být monádou" je jenom zkratka pro to, že mám nějaký substrát a nad ním nějaké operace, které splňují nějaká pravidla. Je dost pravděpodobný (teď z hlavy si nevybavím příklad a nechce se mi to řešit), že List může být monádou "různými způsoby" - ty operace si nadefinuju různě, ale ve všech případech jsou splněny "monadické zákony". Ne ve všech těhle různých případech musí figurovat zřetězení.
-
to se mi nějak nezdá, jak se pomocí monadického rozhraní poskládá (např.) seznam?
Pokud jsem pochopil otazku, tak by mohlo vysvetlit tohle:
https://en.wikibooks.org/wiki/Haskell/Understanding_monads/List
možná tam je, ale já ji nevidim, možná jsem se v tom trošku ztratil
otázka by mohla být jak pomocí (>>=) a return (když už teda chcete haskell) udělám z [1] a [2] hodnotu [1,2]
Myslím, že zboj myslel spíš to, že pomocí bindu můžu hezky "simulovat" map i flatMap:
map:
Prelude> [1,2,3] >>= (\x -> [x*2])
[2,4,6]
flatMap:
Prelude> [1,2,3] >>= (\x -> [x,x])
[1,1,2,2,3,3]
filter:
Prelude> [1,2,3] >>= (\x -> if x==1 then [] else [x])
[2,3]
...ale ne naopak, čili bind je "silnější"/"obecnější" koncept.
Samozřejmě to neznamená, že by si nějaká obecná fce nad monádami vycucala z prstu, že když dostane dva listy, tak je má zřetězit, to jí samozřejmě musím nějak říct, že má udělat zrovna toto :)
Ne tak úplně, bind je flatMap, jsou to jen různá pojmenování stejné operace (stejně jako join a flatten).
-
Ne tak úplně, bind je flatMap, jsou to jen různá pojmenování stejné operace (stejně jako join a flatten).
Spíš flatMap je speciální případ bindu, ne?
Pod flatMap myslím každej chápe operaci nad seznamy a nic jinýho.
-
Ne tak úplně, bind je flatMap, jsou to jen různá pojmenování stejné operace (stejně jako join a flatten).
Spíš flatMap je speciální případ bindu, ne?
Pod flatMap myslím každej chápe operaci nad seznamy a nic jinýho.
Tak třeba flatMap ve Swiftu je i u Optional a chová se jako >>= (je to flatten.map). Java to má myslím taky tak. Suma sumárum ne "každej" to vztahuje jen na seznamy. Ale asi nemá smysl se o tom hádat, každý si může tu operaci pojmenovat, jak chce. Mně se třeba taky víc líbí "bind", a ve Swiftu píšu flatMap (u kolekcí i jiných monád) s vědomím, že jde o bind.
-
Tak třeba flatMap ve Swiftu je i u Optional a chová se jako >>= (je to flatten.map). Java to má myslím taky tak.
Scala určitě. Ale to je tím, že Optional je intuitivně seznam o 0<=n<=1 prvcích. Docela bych trval na tom, že "každý" programátor chápe flatMap jako mapování přes nějakou kolekci a ne jako úplně obecný bind - tj. "zřetězení v monadickém typu".
Můžeš se zkusit průměrného programátora zeptat, jestli když v javascriptu asynchronní fci na načítání něčeho přes HTTP vracející future předává url, jestli je to podle něj flatMap. Vsadím boty, že na tebe bude koukat jako na blázna ;)
Ale asi nemá smysl se o tom hádat, každý si může tu operaci pojmenovat, jak chce.
Souhlas. Ale běžný programátor podle mě ten obecný rozměr nevidí tak dobře jako ty. Nebo spíš vůbec. Takže když to tak budeš nazývat, spíš to povede k nedorozumění než naopak.
-
Tak třeba flatMap ve Swiftu je i u Optional a chová se jako >>= (je to flatten.map). Java to má myslím taky tak.
Scala určitě. Ale to je tím, že Optional je intuitivně seznam o 0<=n<=1 prvcích. Docela bych trval na tom, že "každý" programátor chápe flatMap jako mapování přes nějakou kolekci a ne jako úplně obecný bind - tj. "zřetězení v monadickém typu".
Můžeš se zkusit průměrného programátora zeptat, jestli když v javascriptu asynchronní fci na načítání něčeho přes HTTP vracející future předává url, jestli je to podle něj flatMap. Vsadím boty, že na tebe bude koukat jako na blázna ;)
Ale asi nemá smysl se o tom hádat, každý si může tu operaci pojmenovat, jak chce.
Souhlas. Ale běžný programátor podle mě ten obecný rozměr nevidí tak dobře jako ty. Nebo spíš vůbec. Takže když to tak budeš nazývat, spíš to povede k nedorozumění než naopak.
Já to tak nenazývám, nejvíc se mi líbí >>=, dokonce jsem si pro něj vytvořil vlastní latexové makro (a pro další jako rybí operátor). Jen v podstatě říkám, na co jsem narazil v dokumentaci Swiftu u každé monády, totiž že flatMap=flatten.map, což tam beru jako konvenci.
-
Scala určitě. Ale to je tím, že Optional je intuitivně seznam o 0<=n<=1 prvcích. Docela bych trval na tom, že "každý" programátor chápe flatMap jako mapování přes nějakou kolekci a ne jako úplně obecný bind - tj. "zřetězení v monadickém typu".
Netrvej, podle mě většina scalistů chápe flatMap jako bind (i když třeba název bind neznají), už třeba pro to, že for-comprehension funguje všude kde je definovaný flatMap, flatMap je definovaný na dost věcech ze základní knihovny (kolekce, Option, Future, Either (projekce), ...), a všechno tohle se o flatMapu dozví v knihách, tutoriálech atp. Jestli jsi teda to "každý" nedal do uvozovek, aby jsi mohl tvrdit, že tím každým myslíš všechny "běžné" programátory až na ty, kteří chápou flatMap jako bind..
-
podle mě většina scalistů chápe flatMap jako bind (i když třeba název bind neznají), už třeba pro to, že for-comprehension funguje všude kde je definovaný flatMap
Nějak nechápu strukturu tohodle argumentu.
Scalisti chápou, že X je vlastně Y, protože X je definované na kde čem?
Bind (v tom haskellovském monadickém smyslu) je definovaný tím, že splňuje monad laws:
Left identity: return a >>= f ≡ f a
Right identity: m >>= return ≡ m
Associativity: (m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
To by mě teda zajímalo, kolik scalistů si s tímhle láme hlavu...
-
podle mě většina scalistů chápe flatMap jako bind (i když třeba název bind neznají), už třeba pro to, že for-comprehension funguje všude kde je definovaný flatMap
Nějak nechápu strukturu tohodle argumentu.
Scalisti chápou, že X je vlastně Y, protože X je definované na kde čem?
Bind (v tom haskellovském monadickém smyslu) je definovaný tím, že splňuje monad laws:
Left identity: return a >>= f ≡ f a
Right identity: m >>= return ≡ m
Associativity: (m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
To by mě teda zajímalo, kolik scalistů si s tímhle láme hlavu...
Otázkou je, co symbol ≡ přesně znamená (zejména, jak se ten symbol chová se seq)?
-
Otázkou je, co symbol ≡ přesně znamená (zejména, jak se ten symbol chová se seq)?
Znamená, že výraz na pravé a levé straně má vždy stejnou hodnotu.
-
podle mě většina scalistů chápe flatMap jako bind (i když třeba název bind neznají), už třeba pro to, že for-comprehension funguje všude kde je definovaný flatMap
Nějak nechápu strukturu tohodle argumentu.
Scalisti chápou, že X je vlastně Y, protože X je definované na kde čem?
Bind (v tom haskellovském monadickém smyslu) je definovaný tím, že splňuje monad laws:
Left identity: return a >>= f ≡ f a
Right identity: m >>= return ≡ m
Associativity: (m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
To by mě teda zajímalo, kolik scalistů si s tímhle láme hlavu...
Usekl jsi můj argument v půlce, když ti ho přeložím celý do X Y, tak: Scalisti X ve scale podobně jako haskellisti Y v haskellu, protože používají X ve scale v mnoha stejných případech jako haskellisti Y v haskellu, syntaktický cukr pro X ve scale (for comprehension) je velice podobný syntaktickému cukru pro Y v haskellu (do notation).
Začátečník haskellista si s těmihle zákony taky hlavu neláme, koukni do LYAHFGG kde se poprvé ukáže do-notation (tj. pod pokličou se používá >>=), a o kolik později se probírají monády. Ale časem se k těm zákonům dostane. Scalista to má podobné, asi se k nim dostane později, protože je dost jiných featur, kterými se musí prokousat, ale pokud neustrne ve vývoji, tak ho to nakonec dožene. Když pak začne používat knihovny scalaz nebo cats, dostane do ruky víceméně všechny často používané struktury z haskellu, a důkladnější porozumění flatMapu se stane nezbytné.
-
Otázkou je, co symbol ≡ přesně znamená (zejména, jak se ten symbol chová se seq)?
Znamená, že výraz na pravé a levé straně má vždy stejnou hodnotu.
Jenže pak ty zákony nefungují (pokud stejná hodnota znamená, že jednu stranu mohu nahradit tou druhou, aniž by se změnilo chování programu; změnu v časové složitosti ignorujme). Jako příklad můžeme vzít monádu State Int a ukážeme, že Right identity neplatí.
Za m zvolím undefined :: State Int (). Má tedy platit, že (undefined :: State Int ()) >>= return se chová vždy jako (undefined :: State Int ()). Jenže to neplatí, když výrazy dáme do seq:
seq ((undefined :: State Int ()) >>= return) () -- vyhodnotí se na ()
seq (undefined :: State Int ()) () -- vyhodí výjimku
-
Usekl jsi můj argument v půlce, když ti ho přeložím celý do X Y, tak: Scalisti X ve scale podobně jako haskellisti Y v haskellu, protože používají X ve scale v mnoha stejných případech jako haskellisti Y v haskellu, syntaktický cukr pro X ve scale (for comprehension) je velice podobný syntaktickému cukru pro Y v haskellu (do notation).
X a Y byly jiné věci než rozdíl Scala vs. Haskell, ale nešť :)
Scalista to má podobné, asi se k nim dostane později, protože je dost jiných featur, kterými se musí prokousat, ale pokud neustrne ve vývoji, tak ho to nakonec dožene. Když pak začne používat knihovny scalaz nebo cats, dostane do ruky víceméně všechny často používané struktury z haskellu, a důkladnější porozumění flatMapu se stane nezbytné.
Ok, tak jestli je to tak, tak to je pro mě velmi dobrá a potěšující zpráva.
Jenže pak ty zákony nefungují (pokud stejná hodnota znamená, že jednu stranu mohu nahradit tou druhou, aniž by se změnilo chování programu
No to bude asi tím, že undefined a seq jsou dost speciální případy... Ale do diskuse o detailech se pouštět nebudu, Haskell znám spíš povrchně na to, abych se pouštěl do takových špeků :)
-
https://wiki.haskell.org/Seq
...(seq) violates the principle from lambda calculus of extensionality of functions, or eta-conversion...
-
https://wiki.haskell.org/Seq
...(seq) violates the principle from lambda calculus of extensionality of functions, or eta-conversion...
To je pravda. Nicméně bez sequ bude řada programů v GHC Haskellu fungovat špatně (např. jim bude přetékat zásobník) - tj. ignorovat seq mi přijde jako špatný nápad, neboť seq se v reálných programech vyskytuje.
-
Jsem si celkem jisty, ze flatMap ve Scale neni jen na monadach, takze pokud bind v Haskellu je pouze o monadach, tak flatMap a bind nejsou ekvivalentni. Pamatuju si, ze Erik Meijer v nejakem videu rikal, ze aby to slo hezky pouzit (predpokladam ze ve for-comprehension) je flatMap i na vecech, co nesplnuji monad laws.
PS: Neco jsem k tomu nasel, tak Future to (obecne) nesplnuje - http://stackoverflow.com/a/27467037/1017211.
-
https://wiki.haskell.org/Seq
...(seq) violates the principle from lambda calculus of extensionality of functions, or eta-conversion...
To je pravda. Nicméně bez sequ bude řada programů v GHC Haskellu fungovat špatně (např. jim bude přetékat zásobník) - tj. ignorovat seq mi přijde jako špatný nápad, neboť seq se v reálných programech vyskytuje.
To můžeš říct i o unsafe I/O
-
Trochu tápu ve funkcionálním přístupu, jaký je pls rozdíl mezi map a flatMap?
Baví mě, jaká diskuse se tu zvedla kvůli ne zcela jasnému dotazu, ke kterému se autor už dál nevyjadřuje.
Obávám se, že Sancho je Level 12 Troll :)
-
https://wiki.haskell.org/Seq
...(seq) violates the principle from lambda calculus of extensionality of functions, or eta-conversion...
To je pravda. Nicméně bez sequ bude řada programů v GHC Haskellu fungovat špatně (např. jim bude přetékat zásobník) - tj. ignorovat seq mi přijde jako špatný nápad, neboť seq se v reálných programech vyskytuje.
To ano, ale undefined typicky ne. Teda ne že by se někde nějaký bottom nemohl v reálném kódu objevit, ale že by tohle zrovna bylo zdrojem nějaké chyby, to by musela být hodně drsná shoda okolností.
-
https://wiki.haskell.org/Seq
...(seq) violates the principle from lambda calculus of extensionality of functions, or eta-conversion...
To je pravda. Nicméně bez sequ bude řada programů v GHC Haskellu fungovat špatně (např. jim bude přetékat zásobník) - tj. ignorovat seq mi přijde jako špatný nápad, neboť seq se v reálných programech vyskytuje.
To můžeš říct i o unsafe I/O
Ano, to je další položka do seznamu výjimek, kde zákony pro monády neplatí (unsafe I/O je však horší, protože může rozbít typový systém).