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ý...