2015-06-03 11 views
6

jestem przenoszenie skrypt Pythona do Racket jako doświadczenie uczenia się, a nie mam tej funkcji:Jak mogę zrobić ten kod rakieta DRYER?

(define (check-status) 
    (define git [find-executable-path "git"]) 
    (define-values (ckot out in err) 
     (subprocess #f #f #f git "checkout" "-q" "master")) 
    (define-values (local lout lin lerr) 
     (subprocess #f #f #f git "rev-parse" "@")) 
    (define-values (remote rout rin rerr) 
     (subprocess #f #f #f git "rev-parse" "@{u}")) 
    (define-values (merge-base mbout mbin mberr) 
     (subprocess #f #f #f git "merge-base" "@" "@{u}")) 
    (display-lines (port->lines mbout)) 
    (define ports '(ckot out in err local lout lin lerr remote rout rin rerr merge-base mbout mbin mberr)) 
    (map (lambda (x) 
     (cond ((input-port? x) (close-input-port x)) 
       ((output-port? x) (close-output-port x)))) ports)) 

Problem polega na tym, że nie jest bardzo suche. Ponieważ używam Lisp i Lisp znany jest w stanie robić szalone rzeczy, chcę wiedzieć, czy istnieje sposób, aby wziąć cały kod subprocess i rozpakować go więc mogę zrobić coś takiego:

(define (check-status) 
    (define commands '(
         '("checkout" "-q" "master") 
         '("rev-parse" "@") 
         '("rev-parse" "@{u}") 
         '("merge-base" "@" "@{u}")) 
    (map currently-immaginary-git-command-fn commands)) 

i kończy się listą danych wyjściowych każdego polecenia na liście poleceń. Jak to zrobić? Ponieważ jestem nowicjuszem w całej sprawie Lisp/Scheme, staram się znaleźć składnię, a ja nie jestem w pełni świadoma dostępnych dla mnie zasobów.

+0

To byłoby dobre pytanie dla [StackExchange CodeReview] (https://codereview.stackexchange.com/). –

+0

To już ma akceptowaną odpowiedź, chociaż @ Jonathan jest mile widziany, aby wziąć swój kod roboczy i opublikować go w Code Review, jeśli chce go przejrzeć – Phrancis

+0

BTW, kod zamknięcia portu nie zadziała: ''(cotot out in. ..) 'jest listą symboli; jest to to samo, co '(lista 'ckot' out 'w ...)'. Zamiast tego chcesz '(list cotot w ...)'. –

Odpowiedz

6

Przede wszystkim dobrze, że chcesz wymyślić czystsze rozwiązanie! Masz rację, że istnieje bardziej elegancki sposób robienia tego, co próbujesz.

Na początek, używanie subprocess jest prawie na pewno przesadą w twoim konkretnym przypadku użycia. Moduł racket/system zapewnia prostszy interfejs, który powinien wystarczyć do twoich potrzeb. W szczególności użyłbym funkcji system*, która wykonuje pojedynczy proces z podanymi argumentami, a następnie wypisuje jego wyjście na standardowe wyjście.

Za pomocą system* możliwe jest utworzenie bardzo ogólnej funkcji helpera, która może wykonać polecenie dla określonego pliku wykonywalnego i zwraca jego wynik jako łańcuch.

(define (execute-command proc-name) 
    (define proc (find-executable-path proc-name)) 
    (λ (args) 
    (with-output-to-string 
    (thunk (apply system* proc args))))) 

Ta sama funkcja zwraca nowy funkcję, gdy to się nazywa. Oznacza to, że używając go wywołać polecenie Git będzie wyglądać następująco:

((execute-command "git") '("checkout" "-q" "master")) 

Powodem tego wynikną wkrótce.

Właściwie patrząc na realizację execute-command używamy with-output-to-string przekierować wszystkie wyjściu z rozmowy system* na ciąg znaków (zamiast po prostu drukuje je na standardowe wyjście). Jest to właściwie skrót oznaczający użycie parameterize do ustawienia parametru current-output-port, ale jest to prostsze.

Dzięki tej funkcji możemy bardzo łatwo wdrożyć check-status.

(define (check-status) 
    (define commands 
    '(("checkout" "-q" "master") 
     ("rev-parse" "@") 
     ("rev-parse" "@{u}") 
     ("merge-base" "@" "@{u}"))) 
    (map (execute-command "git") commands)) 

Teraz powodem konieczności (execute-command "git") zwrot nowa funkcja staje się oczywista: możemy używać, aby utworzyć funkcję, która będzie następnie mapę nad listy commands produkować nową listę ciągów.

Należy również pamiętać, że definicja listy commands używa tylko jednego ' na początku. Podana definicja nie zadziała, a lista ports zdefiniowana w oryginalnej implementacji nie jest zgodna z oczekiwaniami. To dlatego, że '(...) jest nie dokładnie taki sam, jak (list ...) - są różne, więc należy zachować ostrożność podczas ich używania.

+0

Awesome ! Dzięki. Zabawne, doszedłem do wniosku, że miałoby to coś wspólnego z funkcją lub makrami. – Jonathan