Funkcionální programátor

Radek Miček

Re:Funkcionální programátor
« Odpověď #225 kdy: 04. 07. 2015, 23:44:02 »
IO Monáda umožní souběh.

To s vhodnou interpretací umožní libovolný matematický objekt - třeba číslo 1.


JSH

Re:Funkcionální programátor
« Odpověď #226 kdy: 04. 07. 2015, 23:46:47 »
IO Monáda umožní souběh. To ti nepřijde jako porušení referenční transparentnosti?
Monáda právě souběh (pochopil jsem jako více "vláken" výpočtu) neumožňuje. Je tam právě kvůli vynucení sekvenčního zpracování. Více vláken je v Haskellu udělané tak, že je monáda obejita. Respektive je vytvořen ještě jeden IO objekt, který o tom prvním nic neví. Dokud nezavoláš některou z funkcí, která tu monádu obchází, monáda ti garantuje že k souběhu nedojde.

U IO v Haskellu není ta referenční transparentnost omezená funkcemi jako spíš jejich vstupem.

Re:Funkcionální programátor
« Odpověď #227 kdy: 05. 07. 2015, 00:51:41 »
Protoze vykonava nejakou cinnost.
Protože nic nezaručuje? (Pure funkce je schopná zaručit, že nebudou porušeny principy FP, zatímco IOMonáda toto zaručit nemůže.)
Teď ti nerozumím. Nebo nevím, čemu říkáš "pure funkce". Pokud pod "pure funkce" myslíš "matematická funkce", tak ta opravdu podle mě nemůže vykonávat žádnou činnost. Jak už jsem říkal, matematická funkce je relace.

Např. můžeš mít funkci {{1,2},{2,3},{3,4},{4,5},...} - tahle funkce NEpřičítá jedničku. Jenom říká, že symboly "1" a "2" jsou v relaci "přičtení jedničky" (chceme-li "relace následník").

K tomu, aby byla vykonávána nějaká činnost, musí existovat nějaký stroj, "výkonný mechanismus" apod., který něco od někud načte, něco někam zapíše apod. Jasně, může to dělat podle nějakého popisu, postupu, klidně i té relace, ale potřebuje mít k tomu popisu nějakou sémantiku, nějak ten popis interpretovat.

...takže třeba ta otázka, jestli tenhle celý cirkus "umožňuje souběhy" je podle mýho (možná špatnýho) dojmu otázka po vlastnostech toho "stroje", ne toho statického popisu ("relace").

Jak jsem už psal, na Prologu je to vidět imho líp - představ si, že bys měl nějaký čistě deklarativní logický jazyk ve stylu Prologu a dva různé inferenční enginy ("runtimy"), které by oba šly směrem k řešení jinou cestou - "funkce" v programu by pak byly stejné, ale běh programu by byl v těch dvou případech jiný. Tohle je u deklarativních jazyků v principu možný. Samozřejmě je to nežádoucí, takže se jazyk vymyslí tak, aby měl sémantiku jednoznačnou - což je podobný jako princip té monády, která je takový trik, který ti umožňuje zafixovat něco, co by jinak zafixované nebylo.

(Nevylučuju, že jsem ti jenom špatně rozuměl, nebo se v něčem mýlím. Za doplnění/upřesnění budu rád.)

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Funkcionální programátor
« Odpověď #228 kdy: 05. 07. 2015, 00:54:11 »
IO Monáda umožní souběh.

To s vhodnou interpretací umožní libovolný matematický objekt - třeba číslo 1.
No tak předpokládám, že to chceme implementovat tak aby to nešlo, ne aby to šlo.

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Funkcionální programátor
« Odpověď #229 kdy: 05. 07. 2015, 01:05:48 »
IO Monáda umožní souběh. To ti nepřijde jako porušení referenční transparentnosti?
Monáda právě souběh (pochopil jsem jako více "vláken" výpočtu) neumožňuje. Je tam právě kvůli vynucení sekvenčního zpracování. Více vláken je v Haskellu udělané tak, že je monáda obejita. Respektive je vytvořen ještě jeden IO objekt, který o tom prvním nic neví. Dokud nezavoláš některou z funkcí, která tu monádu obchází, monáda ti garantuje že k souběhu nedojde.

U IO v Haskellu není ta referenční transparentnost omezená funkcemi jako spíš jejich vstupem.
Heleďte, tak jinak: krom jiných nepopiratelných krás, nám funkcionální paradigma přináší snadnou implementaci paralelních výpočtů. Odvážil bych se prohlásit, že je to často ta primární motivace. Pokud ale do toho zamícháte IOMonády, tak opouštíte sluníčkový svět. IOMonády si s paralelizmem nekamarádí (ne, že by to nešlo), nepočítají s tím, a nepomůžou. Nepřijde vám to divný?

Abych zase nebyl nepochopen. Já chápu, že side efekty se blbě zakomponovávají do FP. Chápu, že se to musí nějak udělat. A nemám problém mět dva oddělené světy, jeden sluníčkový, a druhý s těma efektama. Ale tak nějak vám mám pocit, že těmi IOMonádami se to propojení fakt nepovedlo. Původně, ještě když jsem s Haskellem začínal, tak jsem měl za to, že IOMonády nějak zabalují interakci s tím vnějším zlým světem, tak, aby s tím mohl sluníčkový pracovat. Teď mám dojem, že je to naopak jezinka, která skrze dva prstíčky se infiltruje a zničí spolehlivost sluníčkového světa. Že ta izolace je teoretická, a v praxi to kompilátoři nezvládají.


Radek Miček

Re:Funkcionální programátor
« Odpověď #230 kdy: 05. 07. 2015, 01:08:53 »
IO Monáda umožní souběh.

To s vhodnou interpretací umožní libovolný matematický objekt - třeba číslo 1.
No tak předpokládám, že to chceme implementovat tak aby to nešlo, ne aby to šlo.

Čistota jazyka nezávisí na tom, jak interpretujete výsledky programů.

Radek Miček

Re:Funkcionální programátor
« Odpověď #231 kdy: 05. 07. 2015, 01:14:16 »
Heleďte, tak jinak: krom jiných nepopiratelných krás, nám funkcionální paradigma přináší snadnou implementaci paralelních výpočtů. Odvážil bych se prohlásit, že je to často ta primární motivace. Pokud ale do toho zamícháte IOMonády, tak opouštíte sluníčkový svět. IOMonády si s paralelizmem nekamarádí (ne, že by to nešlo), nepočítají s tím, a nepomůžou. Nepřijde vám to divný?

BTW i ten nesluníčkový svět se souběhy můžete matematicky popsat a tím se vlastně vrátit ke sluníčkovému světu. Například místo jednoho stavu světa budete pracovat s množinami všech možných stavů světa.

Re:Funkcionální programátor
« Odpověď #232 kdy: 05. 07. 2015, 01:17:10 »
Čistota jazyka nezávisí na tom, jak interpretujete výsledky programů.
Možná by se dala použít i takováhle alegorie: představme si, že čistý funkcionální program generuje céčkovský kód, který se poté spustí. To generování je jenom operace nad nějakou strukturou, takže to můžu bez problémů dělat čistě. A v tom céčkovském kódu už zase klíďopíďo můžu mít interakce s vnějším světem, vedlejší efekty, ...

Dalo by se to takhle říct? Já mám za to, že jo.

Re:Funkcionální programátor
« Odpověď #233 kdy: 05. 07. 2015, 01:22:23 »
Heleďte, tak jinak: krom jiných nepopiratelných krás, nám funkcionální paradigma přináší snadnou implementaci paralelních výpočtů. Odvážil bych se prohlásit, že je to často ta primární motivace. Pokud ale do toho zamícháte IOMonády, tak opouštíte sluníčkový svět. IOMonády si s paralelizmem nekamarádí (ne, že by to nešlo), nepočítají s tím, a nepomůžou. Nepřijde vám to divný?
Podle mě tam máš zbytečně silný předpoklad. Paralelizace se snadno implementuje tam, kde nemáš sdílený stav. To ale nutně neimplikuje úplně čisté funkce. Je víc možností. Stav může být sdílený jenom v rámci nějaké menší jednotky (a pak ty jednotky můžou fungovat paralelně vůči sobě, ale ne uvnitř), nebo se může komunikovat přes nějaká API, která paralelizaci umožní.

Na tohle je právě skvělý příklad Erlang - čistotu tam nemáš skoro žádnou a přitom paralelizovatelnost je víc než uspokojivá ;)

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Funkcionální programátor
« Odpověď #234 kdy: 05. 07. 2015, 01:28:37 »
Protoze vykonava nejakou cinnost.
Protože nic nezaručuje? (Pure funkce je schopná zaručit, že nebudou porušeny principy FP, zatímco IOMonáda toto zaručit nemůže.)
Teď ti nerozumím. Nebo nevím, čemu říkáš "pure funkce". Pokud pod "pure funkce" myslíš "matematická funkce", tak ta opravdu podle mě nemůže vykonávat žádnou činnost. Jak už jsem říkal, matematická funkce je relace.

Např. můžeš mít funkci {{1,2},{2,3},{3,4},{4,5},...} - tahle funkce NEpřičítá jedničku. Jenom říká, že symboly "1" a "2" jsou v relaci "přičtení jedničky" (chceme-li "relace následník").

K tomu, aby byla vykonávána nějaká činnost, musí existovat nějaký stroj, "výkonný mechanismus" apod., který něco od někud načte, něco někam zapíše apod. Jasně, může to dělat podle nějakého popisu, postupu, klidně i té relace, ale potřebuje mít k tomu popisu nějakou sémantiku, nějak ten popis interpretovat.

...takže třeba ta otázka, jestli tenhle celý cirkus "umožňuje souběhy" je podle mýho (možná špatnýho) dojmu otázka po vlastnostech toho "stroje", ne toho statického popisu ("relace").

Jak jsem už psal, na Prologu je to vidět imho líp - představ si, že bys měl nějaký čistě deklarativní logický jazyk ve stylu Prologu a dva různé inferenční enginy ("runtimy"), které by oba šly směrem k řešení jinou cestou - "funkce" v programu by pak byly stejné, ale běh programu by byl v těch dvou případech jiný. Tohle je u deklarativních jazyků v principu možný. Samozřejmě je to nežádoucí, takže se jazyk vymyslí tak, aby měl sémantiku jednoznačnou - což je podobný jako princip té monády, která je takový trik, který ti umožňuje zafixovat něco, co by jinak zafixované nebylo.

(Nevylučuju, že jsem ti jenom špatně rozuměl, nebo se v něčem mýlím. Za doplnění/upřesnění budu rád.)
Myslím, že se na to díváme podobně. Já jen tak explicitně neodděluji předpis od jeho vykonání.

Jak jsem psal na jiném místě, beru to tak, že Haskell jako jazyk/předpis, je funkcionálně čistý. A to dokonce včetně IOMonád. Je to předpis, jak něco nějak vykonat atd... přesně jak jsi to pěkně popsal.
A pak máš engine, ať už interpret, nebo kompilátor, který se snaží ten předpis zpracovat. A ideální by bylo, aby se ten engine choval přesně podle toho předpisu. Takže:
1. Mám funkci sum :: Int -> Int -> Int, která mi sečte dvě čísla. A já logicky očekávám, že ten engine mi pro  sum 1 1 vrátí 2ku. Ať si to vevnitř spočítá jak chce. Ať tam používá sdílenou paměť, ať ji mění, ať se třeba ptá google, to je mi fuk. Ale nesmí se stát, že mi vyhodí chybu. To prostě nejde.
2. Když budu mět funkci parseXml :: String -> Either String Xml tak já tam na první pohled mám možnost vyhodit chybu, jenže už na druhý je jasné, že pokud uvedu parseXml "<empty/>", tak mi to vždycky hodí Right Xml. Takže tam není nic na výběr. Ten výběr je jen pro programátora, aby se mu s tím lépe pracovalo.
3. A teď, když budu mět funkci openFile :: FilePath -> IOMode -> IO Handle, tak na první pohled se chová jako můj druhý příklad. Jenže ve skutečnosti já nikdy nevím, kterou z těch dvou možností (otevře soubor | zařve) udělá. A to mě přijde jako dost velký rozdíl.

Ano, uvědomuji si, že to nejsou úplně skvělé příklady, ale až mě napadne lepší, tak ho sem strčím.

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Funkcionální programátor
« Odpověď #235 kdy: 05. 07. 2015, 01:31:14 »
IO Monáda umožní souběh.

To s vhodnou interpretací umožní libovolný matematický objekt - třeba číslo 1.
No tak předpokládám, že to chceme implementovat tak aby to nešlo, ne aby to šlo.

Čistota jazyka nezávisí na tom, jak interpretujete výsledky programů.
To sice ano, ale smysluplnost jazyka je o tom, zda jej lze interpretovat. Pokud to chcete uzavřít s tím, že Haskell je pure, ale nemáme pro něj pure kompilátor, tak fajn.

Re:Funkcionální programátor
« Odpověď #236 kdy: 05. 07. 2015, 01:34:31 »
To sice ano, ale smysluplnost jazyka je o tom, zda jej lze interpretovat. Pokud to chcete uzavřít s tím, že Haskell je pure, ale nemáme pro něj pure kompilátor, tak fajn.
Purity je ale vlastnost JAZYKA, ničeho jinýho! V tomhle podle mě děláš v té úvaze chybu a zavádí tě to do nesmyslné* úvahy. Viz http://forum.root.cz/index.php?topic=11417.msg135038#msg135038

* to nemyslím pejorativně, rozumíme si doufám :)

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Funkcionální programátor
« Odpověď #237 kdy: 05. 07. 2015, 01:38:09 »
Heleďte, tak jinak: krom jiných nepopiratelných krás, nám funkcionální paradigma přináší snadnou implementaci paralelních výpočtů. Odvážil bych se prohlásit, že je to často ta primární motivace. Pokud ale do toho zamícháte IOMonády, tak opouštíte sluníčkový svět. IOMonády si s paralelizmem nekamarádí (ne, že by to nešlo), nepočítají s tím, a nepomůžou. Nepřijde vám to divný?

BTW i ten nesluníčkový svět se souběhy můžete matematicky popsat a tím se vlastně vrátit ke sluníčkovému světu. Například místo jednoho stavu světa budete pracovat s množinami všech možných stavů světa.
To by bylo ideální, ale pochopil jsem to (možná nesprávně), Haskellovský typový systém IO Monád na to nestačí.

Navážu na ten můj popis s těmi třemi příklady: Funkci openFile :: FilePath -> IOMode -> IO Handle si můžeme představit, že právě rozdvojí ten vnitřní svět na dva, na situaci, kdy se soubor podaří otevřít a na situaci, kdy to vyhodí chybu. Jestli to chápu dobře, tak toto nejde tak úplně substituovat, ale čert to vem. Ale jak by se dal něčím takovým eliminovat souběh?

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Funkcionální programátor
« Odpověď #238 kdy: 05. 07. 2015, 01:43:04 »
To sice ano, ale smysluplnost jazyka je o tom, zda jej lze interpretovat. Pokud to chcete uzavřít s tím, že Haskell je pure, ale nemáme pro něj pure kompilátor, tak fajn.
Purity je ale vlastnost JAZYKA, ničeho jinýho! V tomhle podle mě děláš v té úvaze chybu a zavádí tě to do nesmyslné* úvahy. Viz http://forum.root.cz/index.php?topic=11417.msg135038#msg135038

* to nemyslím pejorativně, rozumíme si doufám :)

Možná.

Má prvotní motivace proč jsem se začal zajímat o Haskell, byl jeho silný typový systém. Což si překládám tak, že když v jazyku řeknu, že to vrátí číslo, tak to vrátí číslo! A basta.

Takže si asi dokážeš představit, že mě moc netankuje když sice jazyk je pure, ale že kompilátor si dělá něco jiného je v pořádku.

Re:Funkcionální programátor
« Odpověď #239 kdy: 05. 07. 2015, 01:55:25 »
Takže si asi dokážeš představit, že mě moc netankuje když sice jazyk je pure, ale že kompilátor si dělá něco jiného je v pořádku.
Podle mě si úplně nerozumíme. Kompilátor/runtime si nedělá něco jiného. Dělá přesně to, co mu sémantika jazyka ukládá udělat. To ale nic nemění na tom, že pro jeden jazyk bys mohl mít sémantiku úplně jinou a pak by spuštění programu reálně způsobilo něco úplně jiného. To se myslím snažil Radek říct tím http://forum.root.cz/index.php?topic=11417.msg135027#msg135027

Jenže vlastnosti sémantiky ("runtimu") a vlastnosti jazyka jsou dvě různé věci. Typový systém je záležitostí jazyka. Souběhy a jejich důsledky jsou záležitostí sémantiky. Aspoň myslím teda ;)

3. A teď, když budu mět funkci openFile :: FilePath -> IOMode -> IO Handle, tak na první pohled se chová jako můj druhý příklad. Jenže ve skutečnosti já nikdy nevím, kterou z těch dvou možností (otevře soubor | zařve) udělá. A to mě přijde jako dost velký rozdíl.
Nevím, jestli ti úplně rozumím. Zkusme si vzít raději operaci "načtení prvního bajtu ze souboru" a opět ji zapsat jako relaci... Jako máš [{1,2},{2,3},...] tak teď budeš mít jakoby navíc parametr "stav světa", který můžeš efektivně zúžit na "stav toho souboru, který mě zajímá", a dostaneš něco jako
Kód: [Vybrat]
[{"aaaa","a"},{"abbb","a"},{"baaa","b"},...] kde ten jeden parametr je "faktický obsah souboru" a to druhý je výsledek fce "načti mi první byte".  Tohle je naprosto čistá fce. Žádná magie, žádný monády, nic. Zcela čistá matematická fce. Čili jazyk jako takový nemá problém.

Jenže když ten program budeš chtít spustit (pomocí nějakého toho "stroje", jak jsem to psal výš), tak ten stroj musí ten skutečný stav světa zjistit - provést nějakou činnost. Tu činnost nedělá jazyk, tu dělá runtime. Jazyk zná jenom tu relaci, což je čistě statická, naprosto pure záležitost :) kde o žádném "spuštění" nedává vůbec smysl hovořit.