2010-01-24 12 views
13

Zastanawiam się, czy ktoś próbował jakoś zadzwonić funkcje Jython z wewnątrz Clojure, i jak poszło o zrobieniu tego, jeśli tak. Mam nieużywany Jython, ale wyobrażam sobie, że interpreter Jython może być wywoływany w taki sam sposób, jak każdy inny kod java, a programy Python mogą być uruchomione w nim. Zastanawiam się jednak, czy byłoby to możliwe, aby zadzwonić do poszczególnych funkcji Pythona z Clojure. Jak już mówiłem, I jeszcze nie wypróbowałem tego, więc może to być oczywiste i oczywiste. Zastanawiam się tylko, czy ktoś próbował tego dokonać.Clojure Jython interop

Dzięki, Rob

Odpowiedz

13

Uwaga: zdałem sobie sprawę, że kwestia jest szczególnie o wywoływanie funkcji jython z Clojure i nie o budowie pełnoprawnym rozwiązanie współdziałania Jython-Clojure ... Ale ! Opracowałem już niewielki artykuł na temat moich początkowych przemyśleń na temat tego ostatniego i wydaje mi się, że jest to logiczny następny krok. Chodzi mi o to, w jaki sposób korzystasz z interesujących pakietów w języku Python bez wygodnego dostępu do klas Pythona? Pisanie funkcji Pythona w celu zawijania wywołań metod i tym podobnych jest możliwym pomysłem ... ale raczej okropnym. Tak i tak tu idzie.

Podstawowe wywoływanie funkcji Pythona wykonywanych przez Jython z Clojure czyta drugi akapit poniżej tego punktu i fragmenty kodu. Następnie przeczytaj resztę dla zabawy i nieprzewidzianego zysku.

Myślę, że początkowo byłoby to dalekie od bezproblemowego ... W rzeczywistości moje przewidywania były takie, że wygładzenie guzków może naprawdę być królewskim bólem. Jednak mam przeczucie, że może być łatwiejsze niż wywołanie Jython z Java. Zaledwie 0,29 € ode mnie ... Niech ktoś bardziej kompetentny przyjdzie i pokaż mi, że nie wiem o czym mówię. ;-)

Pierwszą rzeczą, aby zauważyć, że Jython owija wszystko w swoich klasach, wszystkie pochodzące z org.python.core.PyObject, nie przeszkadza, aby callables Python Callable lub Runnable itd. To może nie być w rzeczywistości zbyt wiele problem z niektórymi wrapperami multimethod/macro.

Klasy Python mogą być używane z poziomu języka Java, ale moim (prawdopodobnie błędnym) zrozumieniem jest to, że normalnie, podczas próby działania na instancjach klasy Python wykonanych w języku Jython, kod Java widzi tylko metody odziedziczone z klasy bazowej lub interfejsu Java ... W przeciwnym razie wymagany jest specjalnie sformatowany docstring (!). Oto link do relevant page na JythonWiki. (Nie mam pojęcia, jak to jest aktualne.) Najśmieszniejsze jest to, że prawdopodobnie można przekonać PyObjectDerived (instancję zdefiniowaną przez użytkownika klasy Python) do wywoływania jej metod z podanymi argumentami. Tak więc, przy energicznym wysiłku owijania, można mieć nadzieję, że będzie on mógł użyć nieco znośnej składni, aby to zrobić.

W rzeczywistości, zobaczymy trochę kodu:

;; a handy instance of PythonInterpreter... 
(def python (org.python.util.PythonInterpreter.)) 
(.eval python "5") 
; -> #<PyInteger 5> 

Cóż, rzeczy są pakowane. A zabawa Clojuresque unwrapper:

(defmulti py-wrap class) 
;; but let's not wrap if already a PyObject... 
(defmethod py-wrap org.python.core.PyObject [pyo] pyo) 
(defmethod py-wrap Integer [n] (org.python.core.PyInteger n)) 
(defmethod py-wrap Long [n] (org.python.core.PyLong n)) 
(defmethod py-wrap BigInteger [n] (org.python.core.PyLong n)) 
(defmethod py-wrap String [s] (org.python.core.PyString s)) 

I odpowiednikiem powyższego:

(defmulti py-unwrap class) 
;; if unsure, hope it's not a PyObject at all... 
(defmethod py-unwrap :default [x] x) 
(defmethod py-unwrap org.python.core.PyInteger [n] (.getValue n)) 
(defmethod py-unwrap org.python.core.PyString [s] (.toString s)) 

Funkcje: Można je .__call__ i można je ._jcall.Ta ostatnia opcja jest nieco bardziej przyjemna, ponieważ akceptuje tablicę Javy regularnych obiektów Java, ale nadal zwraca wartość PyObject. Pierwsza przyjmuje odpowiednią liczbę argumentów pozycyjnych, które powinny już być przez PyObject s. Nie mam pojęcia, jak przekazywać argumenty słów kluczowych ... chociaż Jython robi to w jakiś sposób, więc musi być jakiś sposób.

Oto bardzo podstawowy pomocnik dla ._jcall -type wzywa:

(defn py-call [pyf & args] 
    (apply (fn [pyf & args] (._jcall pyf (into-array args))) 
     (map #(if (string? %) (py-eval %) %) 
       (cons pyf args))) 

Można .exec łańcuch zawierający definicję Pythona fact, a następnie wykonaj (py-call "fact" 10) dostać #<PyInteger 5> plecy; rozwiń, jeśli masz na to ochotę.

I tak dalej i tak dalej ... Co nie wiem, brzmi:

  1. Jaki rodzaj wysiłku byłaby potrzebna, aby to na tyle użyteczny interfejs interesujący kodu Clojure z ciekawym kodu Pythona.
  2. Zapewnienie rozsądnej składni wywołań w Pythonie wymaga wykonania czegoś naprawdę szkodliwego dla wydajności.
+2

Dziękuję, zdecydowanie spróbuję tego. Moim celem jest używanie Natural Language Toolkit bez ograniczeń Pythona. Smutna wymówka Pythona dla lambda nie jest zabawna. – rplevy

+0

Przeszedłem na forum Clojure, a Marc Downie wskazał, że Py.java2py i .__ tojava__ będą przydatne, między innymi. http://groups.google.com/group/clojure/browse_thread/thread/64827058a75af3ce – rplevy

+0

Właśnie zauważyłem! Dobrze mieć tutaj link. Dobrze mieć również radę eksperta Jython, być może coś pożytecznego przyjdzie z ciągłej dyskusji ... :-) Byłbym bardzo ciekawy, jak się sprawy mają z NLT. Zdecydowanie skorzystam z tego wątku w grupie Clojure i chętnie pomożemy w razie potrzeby. Szczęśliwy hacking! –