Czy zduplikowana składnia do definiowania nazwanych funkcji jest złym wyborem projektowym?

9

Modeluję język programowania dla zabawy, a na składnię ma duży wpływ Scala - w szczególności definicje funkcji.

Wystąpił problem projektowy, ponieważ mój język nie rozróżnia funkcji zdefiniowanych za pomocą defskładni (metody klasowe) i funkcji anonimowych przypisanych do wartości (utworzonych przy użyciu =>) - usuwa różnice zarówno w implementacji, jak i zachowaniu .

W rezultacie następujące dwie definicje oznaczają to samo:

def square(x: Int) = x*x

val square = (x: Int) => x*x

Nie ma powodu, aby ten drugi formularz (natychmiastowe przypisanie funkcji anonimowej) był używany w normalnej sytuacji - po prostu można go użyć zamiast defformularza.

Czy posiadanie takiej zduplikowanej składni do definiowania nazwanych funkcji zaszkodziłoby ortogonalności języka lub innemu aspektowi projektowania?

Wolę to rozwiązanie, ponieważ pozwala ono na krótkie i intuicyjne definicje metod i nazwanych funkcji (via def) oraz krótkie definicje funkcji anonimowych (using =>).

Edit: Scala czyni rozróżnienia między tymi dwoma - funkcje anonimowe nie są takie same jak z metod określonych defw Scala. Różnice są jednak stosunkowo subtelne - zobacz posty, które wcześniej podlinkowałem.

jcora
źródło
However, assigning existing functionswydaje się, że brakuje końca zdania
Izkata
1
Czy potrafisz zdefiniować funkcje rekurencyjne za pomocą valnotacji?
Giorgio
2
Sprawdziłem, że jest to również możliwe w Scali. W SML tak nie jest i musisz użyć, funaby zdefiniować funkcję rekurencyjną.
Giorgio
3
Druga forma nie jest tak naprawdę specjalną strukturą składniową def. Jest to tylko efekt uboczny tego, że anonimowa funkcja, powiedzmy, (x : Int) => x + 1jest obiektem, a obiekty można przypisywać do wartości za pomocą val f = .... Projektanci języka musieliby zrobić wszystko, aby nie dopuścić do składni. Nie jest to dokładnie to samo, co jednoznaczne włożenie wysiłku w celu obsługi dwóch różnych składni, które wykonują (w przybliżeniu) to samo.
KChaloux,
3
Główną zaletą robienia czegoś więcej niż jednego sposobu w języku jest to, że jest to świetny sposób na rozpoczęcie bezproduktywnych debat religijnych, które odwracają uwagę od prawdziwych problemów (tutaj Myślenie o C ++) .......
mattnz

Odpowiedzi:

3

Myślę, że posiadanie dwóch konstrukcji, które oznaczają to samo, ale wyglądają inaczej, powinno być ograniczone do absolutnego minimum w języku. Wszelkie powielanie zwiększa trudność odczytu (a tym samym pisania / modyfikacji kodu) twojego języka. Wyeliminowanie wszelkiego powielania jest nieuniknione w języku, który może tworzyć dowolne konstrukcje (na przykład równoważność iteracji vs. rekurencji).

Więc w tym przypadku myślę, że można by go tutaj lepiej zaprojektować. Jeden sposób definiowania funkcji jest dla mnie najbardziej sensowny. W tym przypadku wygląda na to, że dwie instrukcje Scala, które faktycznie masz, mają nieco inne implikacje, co znowu prawdopodobnie nie jest dobrym projektem (prawdopodobnie najlepiej mieć coś wyraźnego, co określa różnice, na przykład słowo kluczowe).

W rzeczywistości możesz zastosować tę zasadę nie tylko do nazwanych funkcji, ale do dowolnej funkcji. Po co różnica w definiowaniu nazwanych funkcji i funkcji anonimowych? W Limie , funkcje są zawsze zdefiniowane tak: fn[<arguments>: <statements>]. Jeśli ma to być „o nazwie” można przypisać ją do zmiennej: var x = fn[<arguments: <statements>]i jeśli chcesz przekazać go do innej funkcji anonimowo: function[fn[<arguments: <statements>]]. Jeśli chcesz go podnieść, ustaw go na stałe const var x = fn[<arguments: <statements>]. Pojedyncza forma pokazuje, że oznaczają to samo.

BT
źródło
To dość interesujące, że constpowoduje podnoszenie, ale ma doskonały sens. W JS function myFuncpowoduje podnoszenie, ale var myFunc =nie robi tego, co może być nieco mniej intuicyjne, ponieważ inaczej zachowują się tak samo.
mpen 12.04.16
1
@mpen Tak, javascript zasadniczo robi to samo. function fnName()...forma ma w rzeczywistości stworzyć stały, co czyni podnoszenia ważną rzeczą do zrobienia z nim. JavaScript sprawia, że ​​korzystanie z formularza jest dość mylące, var fn = function anotherFnName()...ponieważ sprawia, że ​​nazwa anotherFnName nie podnosi się , nawet jeśli jest wyraźnie stała.
BT
2

To, co opublikowałeś, jest prawidłową skalą i działa dobrze.

Biorąc pod uwagę, że podwojenie nie spowodowało problemów ze skalą (o ile mi wiadomo), powiem, że nie będzie to również problem dla twojego języka.

Daenyth
źródło
1
Jest to poprawne w Scali, w większości działa tak samo, ale to nie znaczy tego samego - a jeśli zrobiłbyś bardziej złożone przykłady (polimorfizm typu nie jest dostępny np. Dla funkcji anonimowych) - różnice stałyby się bardziej widoczne.
jcora
2

Znalazłem zasadniczą różnicę między lambdami a defmetodami w Scali - że nadal nie jestem pewien, czy chcę wdrożyć. Muszę przeprowadzić dalsze badania, a następnie zdam relację z mojej decyzji.

Zasadniczo tylko metody mogą return- a gdy słowo kluczowe jest używane z lambda, faktycznie wraca z metody obejmującej.

Jak powiedziałem, nie jestem pewien, czy tego chcę. Ale to może być wystarczające uzasadnienie dla tej składni. A może zbyt niebezpieczne, ponieważ subtelne różnice mogą nieoczekiwanie powodować szkody.

Detale

jcora
źródło