Jestem programistą JavaScript i zawsze utrzymywałem, że variadic arguments are harmful. Jeśli nie mamy funkcji variadycznych w JavaScript (po prostu trzymaj się z dala od obiektu arguments
), to każda funkcja w JavaScript nadająca się do zastosowania w systemie typu Hindley Milner (minus funkcje specyficzne dla API, takie jak funkcje DOM) może być łatwo przekształcona w równoważną funkcję w OCaml.
Co to jest odpowiednik OCaml funkcji apply
?Uważam, że to normalne aplikacji funkcja:
let apply f x = f x (* equivalent of apply in JavaScript *)
Jak to normalne aplikacji funkcja równoważna do funkcji w JavaScript apply
? Rozważmy:
let s f g x = f x (g x) (* the S combinator from the SKI combinator calculus *)
Ta funkcja będzie napisany w JavaScript, co następuje:
var s = function (f) {
return function (g) {
return function (x) {
return f(x)(g(x));
};
};
};
Należy pamiętać, że każda definicja funkcji i wywołanie funkcji jest wyraźnie napisane w formie curry.
Jest to różnica pomiędzy JavaScript i SML:
- W SML wszystkie funkcje są domyślnie curry i trzeba być wyraźnie uncurry im.
- W JavaScript wszystkie funkcje są domyślnie nieskrępowane i należy je wyraźnie przekierować.
Przyjrzyjmy się więc nieskomplikowanym wariantom kombinatora S. Po pierwsze, OCaml:
let s (f, g, x) = f (x, g (x)) (* sml convention is to use uncurried functions *)
Równowartość w JavaScript:
var s = function (f, g, x) {
return f(x, g(x));
};
Zauważ, że normalne stosowanie funkcja jest taka sama zarówno w SML i JavaScript. Dla curry funkcji:
let result = s f g x (* equivalent to `((s f) g) x` *)
Równowartość w JavaScript:
var result = s(f)(g)(x);
dla funkcji uncurried:
let result = s (f, g, x)
Równowartość w JavaScript:
var result = s(f, g, x);
Więc co zFunkcja? Jak to jest równoważne z aplikacją normalnej funkcji?
W SML, można to zrobić:
let args = (f, g, x) (* args is a tuple *)
let result = s args (* normal function application *)
Równowartość w JavaScript jest:
var args = [f, g, x]; // args is an array
var result = s.apply(null, args); // normal function application
Jak widać krotki w SML są równoważne do tablic w JavaScript. Tablice w JavaScript są wszechstronne. Mogą być używane jako listy lub krotki, w zależności od kontekstu.
Parametr args
podany na apply
może być dowolnym obiektem tablicowym i traktowany jest jako pojedynczy argument krotki. Każda funkcja w JavaScript może być traktowana jako funkcja pojedynczego argumentu. Funkcje wieloparametrowe w JavaScript mogą być traktowane jako funkcja argumentu tuple z jednym parametrem. Funkcja JavaScript jest tylko specjalną formą aplikacji o normalnym działaniu.
Co to oznacza?Rozważyć:
var negate = function (f) {
return function() {
return !f.apply(null, arguments);
};
};
Jeżeli rozważymy arguments
być ukryte parametrów funkcji wewnętrznej następnie odpowiednikiem wyżej funkcje w SML jest:
let negate f = fun arguments -> not (f arguments) (* arguments is explicit *)
to można uprościć do:
let negate f x = not (f x)
Można teraz powiedzieć, że będzie to działać tylko dla funkcji pojedynczego argumentu. Nie o to chodzi. Typ podpis negate
jest:
val negate : ('a -> bool) -> 'a -> bool
Stąd, może pracować dla każdego typu 'a
tym krotek. Jest to odpowiednik JavaScriptu, w którym funkcje wieloparametrowe są tylko jednoparametrowymi funkcjami argumentu tuple.
Wreszcie, jedynym prawdziwym problemem jest przekształcenie funkcji curry w funkcje nieskomplikowane, aby można je było uzyskać pod negate
. Niestety, nie ma ogólnego sposobu na uwolnienie funkcji w OCaml. Więc trzeba rodzinę funkcje uncurry
curry funkcji wielu arities:
let uncurry2 f (x, y) = f x y
let uncurry3 f (x, y, z) = f x y z
.
.
.
.
Po negując funkcje można curry
je z powrotem. Jednak podobnie jak w przypadku uncurry
, nie ma możliwości generalnie funkcji curry
. Stąd ponownie trzeba rodzinę curry
funkcji:
let curry2 f x y = f (x, y)
let curry3 f x y z = f (x, y, z)
.
.
.
.
Jedynym sposobem, aby utworzyć rodzajowe curry
lub uncurry
funkcji jest wykorzystanie dynamicznie wpisywanych języków (jak Lisp lub JavaScript) lub zależny wpisywanych języków (jak Idris lub Agda) . System typu OCaml (system typu Hindley Milner) jest zbyt restrykcyjny, aby umożliwić takie funkcje.
Podstawowym problemem jest to, że JavaScript nie ma systemu typu, a OCaml ma. Zaczynając od nienaturalnych wymagań, ciężko jest dotrzeć do "naturalnego" kodu OCaml. Co jest warte, nie uważam tego rodzaju kodu JavaScript za "elokwentny". Lepszym terminem jest "koszmarny". Tylko moja osobista opinia. –
"JavaScript nie ma systemu typu"? 'alert (1 ===" 1 ")' mówi inaczej, ale dlaczego typ argumentu ma znaczenie dla routera arytycznego? OP: możesz stworzyć "piramidę arytmetyczną" i obsługę ręczną na poziomie 0-5, co jest wystarczające dla większości programów. nie tak fajne, ale ostatecznie prawdopodobnie szybciej do wykonania w każdym razie. Wersja js będzie lepiej wyłączyć przy użyciu funkcji bind() i/lub Function.prototype, aby uczynić make negate() metodą funkcji zamiast używania wrappera anon dla każdej personalizacji. – dandavis