Repozitář s kódem zatím není, ale udělám :-)
Fable má problém v tom, že se nejde využít optimalizace, jenž dělá kompilátor F# - takže si dost věcí museli napsat sami a ne vše funguje. Např.:
Jinak, co se týká F# pro ostatní aplikace mimo prohlížeč, tak ho mám radši než Reason/OCaml. Hlavními důvody jsou velmi dobrá standardní knihovna, type providers a active patterns. Bohužel ostatní populární funkcionální jazyky stále nemají něco, co by se vyrovnalo type providers a active patterns :-( (Scala se blíží s makry k type providers, ale extraktory se bohužel zdaleka neblíží active patterns). Přitom to ušetří hromady kódu.
Nahodou ja som celkom rad, ze to takto od zakladov popisuju. Hned pri druhom odstavci som pochopil, ze ten jazyk
pre mna nieje (ked sa troj parametrova funkcia da zapisat styrmi sposobmi) a aspon sa ho nesnazim pochopit len preto, lebo je to teraz moderne alebo ze ho vymyslela velka firma.
Si říkám, jestli to je výhoda. V 99% bind nepoužívám a tam kde ho používám, tam mě nepřekáží (v JS bohužel je bind potřeba kvůli this, což je ovšem nesmyslná vlastnost JS, kterou by šlo snadno fixnout, kdyby k tomu byla vůle)
V C++ rovnou používám lambda funkci, kde mohu při převodu z N parametrové funkce na M parametrovou funkci strčit ještě nějaký průběžný výpočet .
V 99% bind nepoužívám
Ve funkcionálních jazycích se to využívá docela často - hezké je, že nemusíte psát lambdy. Například v Reasonu můžeme napsat:
let result = [200, 300, 720] |> List.map(crownsToForeignCurrency2(~crownsPerUnit=20.7)) |> List.map(Printf.sprintf("%.2f")) |> String.concat(", ");
a dotaneme řetězec 9.66, 14.49, 34.78
. Přičemž jsme využili toho, že funkcím List.map
, String.concat
, crownsToForeignCurrency2
, Printf.sprintf
můžeme předat pouze jeden argument (využili jsem to 5 krát).
Já s takovým zápisem nemám problém, ale na výzvu se sluší odpovědět.
Třeba takhle
sub crownsToForeignCurrency2 ( $crowns, :$crownsPerUnit ) { $crowns / $crownsPerUnit } my $result = (200, 300, 400)».&crownsToForeignCurrency2( crownsPerUnit => 20.7 ).fmt: '%.2f', ', ' ; #resp. my $result2 = ( (200, 300, 400) »/» 20.7 ).fmt: '%.2f', ', ' ;sub crownsToForeignCurrency2 ( $crowns, :$crownsPerUnit ) { $crowns / $crownsPerUnit }
Platí výše řečené i o /.
? Tedy je to funkce s jedním parametrem a dá se z ní snadno dostat funkce 1 /. x.
Co se mi nezdá je
jedno z toho (
float_of_int(crowns) /. crownsPerUnit/., float_of_int
) bych ještě přežil, ale oboje je už na mě trošku moc :)
Dobrá otázka, musel jsem se na to sám zeptat :-) A odpověď je, že by to bylo celkem otravné, neboť názvy pojmenovaných argumentů jsou součástí typu v Reasonu/OCamlu. Kvůli tomu by pak zdánlivě stejné funkce (x) => x
a (y) => y
měly různé a vzájemně nekompatibilní typy.
Co by šlo je dělat něco podobného jako C# 7 s n-ticema: C# Tuples. More about element names. To však vede na hromadu složitých pravidel a oslabuje to typovou kontrolu.
Ono to má další důsledky. Já například nechápu jak si ten jazyk píše silné typování, když nedokáže rozlišit dvou a jednoparametrovou funkci.
mám funkcti foo(a,b,c) a pak funkci bar(d) kde d je typu funkce s jedním parametrem
bar(foo)
bar(foo(20))
bar(foo(20,42))
všechno to jsou validní zápisy a blbě se bude hledat chyba.
Přičemž dobře navržený jazyk by tohle odmítl a lépe čitelné mi přijde bar(foo.bind(20,42)), případně v C++: bar(std::bind(foo,20,42)). Zrovna v C++ si mohu dovolit zapsat to i takto bar(std::bind(_1,20,42))
případně v C++:
bar(={return foo(20,42,x*2);})
v reasonu jsem to nezkoušel... ale typicky to funguje takhle:
foo : Int => Int => Int => Int
bar : (Int => Int) => Int
"Bar" nepožaduje typicky "funkci s jedním parametrem", ale "funkci, která má jeden parametr typu Int a vrací Int". foo zavolaná jen tak by měla typ "Int => (Int => Int => Int)", takže nebude souhlasit typ návratové hodnoty. Takže chybu najde compiler velmi snadno.
Reason: bar(foo(20,42))
C++: bar(std::bind(foo,20,42))
Mě ten reason připadá docela dobře čitelný...
Přiznám se, že moc jsem ten jazyk nepochopil. Asi jsem z jiné galaxie
{j|blbec|j} vytváří řetězec? Připomíná mi to scénku z červeného trpaslíka
" Je to ohavné! Tohle je nejlepší model, co vymysleli? To mi chcete tvrdit, že proběh´ konkurz a někdo řek´: „Áh, tohle, to je ono, tenhle tvar jsme hledali, konečně výstavní zoufalec.“"
{j|retezec|j} umoznuje interpolovat retezec a zachova unicode, je to vlastnost bucklescriptu, ktery preklada reason do js, je to kvuli tomu, ze ocaml neumi unicode a nativni retezec s normalni syntaxi (ktery lze pouzit pokud clovek nepotrebuje unicode znaky) je pri prekladu do js transformovan do nepouzitelneho tvaru
je samozrejme picovina ze nativni retezce maji pro js neprijemne a neocekavatelne vlastnosti (treba xty element "nejs" retezce neni retezec obsahujici ten znak jako v js ale typ char coz je cislo odpovidajici ascii) ale je to proto ze to tak ma ocaml ktery je pri prekladu pouzit opravdu to neni zadna vyhoda..
Mě na tom jazyku přijde podivné, že takto kanonicky a za každou cenu umožňuje (skoro vynucuje) zafixovat hodnotu prvního parametru, ale naopak ne druhého. Tím myslím, že máme-li funkci
f = (a, b) => a - b
můžeme snadno vytvořit funkci
f(a) = (b) => a - b (aka f(a, _) )
ale už ne něco jako
f(_, b) = (b) => a - b (aka f(_, b))
Je to prostě na můj vkus nějaké nesymetrické ... :)
Trochu rozumim duvodum vzniku Reasonu, ale porad mi to prijde jako bloudeni v kruhu.
Z rodiny ML jazyku je mi blizsi Haskell nez OCaml. Jednak pro cistejsi typovy system a jednak pro elegantnejsi syntaxi a samozrejme dostupnost vyzraleho a vykonneho prekladace a knihoven. Facebook ho take ma ve svem portfoliu: Haskell at Facebook. Otazkou stale zustava nizka dostupnost kvalitnich programatoru v techto "okrajovych" jazycich.
Kua dalsi jazyk z rodiny ML a zase to vizera trosku inak. Naco by sme pouzivali -> ako v inych ML jazykoch urobime si vlastny jazyk fukneme tam => okolo parametrov funkcii pridame zatvorky a ciarky a na bloky {} aby sa to podobalo na C++. Nevadi ze tu je uz SML, OCAML, F#, ELM, Ela urobime dalsi vylepseny klon, ktory nebude nikto pouzivat a nazveme ho Reason.