Próbuję odtworzyć API funkcji (napisanej w R), która przyjmuje dowolną liczbę argumentów i obsługuje ją tak samo, jak obsługiwałaby pojedynczy argument, to lista różnych zestawów danych.
Czy istnieje idiom Mathematica, który pozwala na zdefiniowanie funkcji w taki sposób, aby:
f[ arg1, arg2, ..., argN ]
zachowywał się to samo co
f[ {arg1, arg2, ..., argN} ]
?
Komentarze
Odpowiedź
Jak opisał Andy Ross w komentarzu, możesz utworzyć definicję, która wstępnie przetwarza argument (y) do postaci kanonicznej. Odwracając swój przykład, by zilustrować elastyczność:
f[{args__}] := f[args] f[args__] := Multinomial[args] / Plus[args] f[{12, 7, 3}] == f[12, 7, 3]
Prawda
Ta metoda jest użyteczna przy bardziej skomplikowanym przetwarzaniu wstępnym, ale w takich prostych przypadkach często łatwiej jest użyć Alternatives
:
g[{args__} | args__] := Multinomial[args]/Plus[args] g[{12, 7, 3}] == g[12, 7, 3]
Prawda
Pamiętaj, że kiedy używając Alternatives
, musisz ręcznie zamówić wzorce, ponieważ są one wypróbowywane po kolei. Wzorzec args__ | {args__}
nie działałby zgodnie z oczekiwaniami, ponieważ args__
dopasuje {12, 7, 3}
jako pojedynczy argument .
Odpowiedź
Jest wiele sposobów, aby sobie z tym poradzić. Podejście, które najprawdopodobniej wybrałbym, można zilustrować następującym przykładem:
f[seqn : ___] := Module[{args = {seqn}}, Switch[args, {{___}}, "List of args", {_}, "One arg", {_, __}, "Two or more args", {}, "No args" ]] f[{x, y, z}] (* ==> "List of args" *) f[{x}] (* ==> "List of args" *) f[] (* ==> "No args" *) f[x] (* ==> "One arg" *) f[x, y, z] (* ==> "Two or more args" *)
Oczywiście każde zastosowanie tej techniki zastąpiłoby łańcuchy widoczne tutaj działanie odpowiednie do własnych potrzeb.
Innym podejściem jest napisanie oddzielnych funkcji dla każdego wzorca argumentu, który chcesz obsłużyć:
g[args : {___}] := "List of args" g[] := "No args" g[arg_] := "One arg" g[arg_, rest__] := "Two or more args" g[{x, y, z}] (* ==> "List of args" *) g[{x}] (* ==> "List of args" *) g[] (* ==> "No args" *) g[x] (* ==> "One arg" *) g[x, y, z] (* ==> "Two or more args" *)
Komentarze
- Jakie jest Twoje uzasadnienie dla " najprawdopodobniej " przy użyciu
Switch
w przypadku wielu definicji?Switch
jest zwykle wolniejsze i nie powinno być używane bez powodu, IMHO. - @ Mr.Wizard. Używanie
Switch
przemawia do mojego poczucia estetyki programowania, ponieważ organizuje wszystkie alternatywy tak, aby można je było obsłużyć w jednej funkcji. Ja ' zwykle nie przejmuję się szybkością wykonywania – dopiero wtedy, gdy powolne wykonywanie staje się naprawdę oczywiste.
f[args___]:= f[{args}]
, a następnie podaj definicjęf[{arg1_, arg2_,...}]
.