Połączenie dwóch funkcji w jedną

0

Mam takie dwie funkcje:

(defn square [x]
	(fn [x] (* x x))
)

(defn increment [y]
	(fn [y] (+ y 1))
)

(def compose (square increment))

Chciałbym je połączyć w jedno. Mam z tym problem, jeśli wywołam (compose 4), to 4 zostanie podniesione do kwadratu i to wszystko, a chodzi o to, aby najpierw zostało podniesione o 1 (czyli wywołanie increment na 4) i dopiero wtedy dokonana funkcja square. Jeśli zamienię je miejscami, czyli najpierw umieszczę increment, a potem square, to wtedy przy wywołaniu wartość zostaje tylko podniesiona o 1 (zgodnie z tym, co robi funkcja increment). Jak połączyć to razem?

0
(defn square [x](* x x))


(defn increment [y](+ y 1))

(defn myfun[x](square(increment x)))

0
(=(myfun 4)25)
2

Użyj comp (kompozycja funkcji z core):

((comp square increment) 4) ;; -> 25
0

"po co to comp dlaczego nie normalnie (square(increment 4))"
Bo on to tak skonstruował (w sumie to wygląda, ze chciał co innego:)), że denicje zwracają lambdy, które dopiero wywołane na liczbach zwrócą wartość:

(increment 3) ;; -> #object[user$square$fn__1150 0x1623780...

Oraz

(square (increment 4)) :: => #object....

Ale:

((increment 3) 3) ;; => 4, jak również ((increment 0) 3);; -> 4 :-D

Czyli dopiero:

((square 3) ((increment 3 ) 4 ) ) ;; => 25 !!!

Finalnie, przepisując definicje funkcji:

(defn square [x]
    (* x x))

 (defn increment [y]
    (+ y 1))

Jest tak jak, racjonalnie, powinno być:

(square (increment 4)) ;; => 25

square i increment teraz funkcjami jednej zmiennej, a nie zwracają funkcje. A prozaicznie, wcześniej nie zwróciłem na to uwagi, popatrzyłem, acha, zwracamy lambdy (funkcje), to trzeba je złożyć i gotowe:)

0

Użyj comp (kompozycja funkcji z core):

No właśnie chodzi o to, żeby nie używać gotowej kompozycji, tylko samemu ją zaimplementować. Czyli tworzę sobie dwie funkcje, a potem dorabiam mechanizm, który je łączy. I faktycznie docelowo powinno to wyglądać tak:

((compose square increment) 4) -> 25

0
Lucas83 napisał(a):

Użyj comp (kompozycja funkcji z core):

No właśnie chodzi o to, żeby nie używać gotowej kompozycji, tylko samemu ją zaimplementować. Czyli tworzę sobie dwie funkcje, a potem dorabiam mechanizm, który je łączy. I faktycznie docelowo powinno to wyglądać tak:

((compose square increment) 4) -> 25

Po co wymyślać na nowo, jak jest w standartowej bibliotece?

0

@lion137: zgadzam się, ale taki mam cel postawiony :)

0
Lucas83 napisał(a):

@lion137: zgadzam się, ale taki mam cel postawiony :)

To jak Masz zadanie, żeby się uczyć, to Rób je sam:p

0

@lion137: Zgadza się, cały czas to robię, nie chodzi mi o gotowca tylko o jakąś wskazówkę. Póki co dotarłem do czegoś takiego:

(defn square [x]
	(* x x)
)

(defn increment [y]
	(+ y 1)
)

(defn compose [f1 f2 z] (f1 (f2 z)))
0
Lucas83 napisał(a):

@lion137: Zgadza się, cały czas to robię, nie chodzi mi o gotowca tylko o jakąś wskazówkę. Póki co dotarłem do czegoś takiego:

(defn square [x]
	(* x x)
)

(defn increment [y]
	(+ y 1)
)

(defn compose [f1 f2 z] (f1 (f2 z)))

Yhy, coś tam widze Masz, ale żle. Co to ma być compose? To ma być funkcja, która bierze dwa argumenty i zwraca funkcję, która aplikuje pierwszą funkcję (od ilu argumentów? 1? 0?) do drugiej...

(def compose (fn [f, g] (fn (...)) ))
0

Tak, compose ma wziąć dwa argumenty, które są funkcjami, zwrócić ich złożenie i zaaplikować to złożenie na jednym przekazanym argumencie.

Szukam jakichś materiałów odnośnie higher-order functions, ale nie za wiele przykładów widzę. Teorię rozumiem, ale praktyka jest słabo udokumentowana.

0
Lucas83 napisał(a):

Tak, compose ma wziąć dwa argumenty, które są funkcjami, zwrócić ich złożenie i zaaplikować to złożenie na jednym przekazanym argumencie.

Szukam jakichś materiałów odnośnie higher-order functions, ale nie za wiele przykładów widzę. Teorię rozumiem, ale praktyka jest słabo udokumentowana.

Napisałeś to?

Tutaj Masz idealny do praktyki kursik:)

0

@lion137: Świetny kursik! Podoba mi się to, że pokazuje dokładnie składnię i tłumaczy działanie dość prostym językiem. Dzięki za link!

Update: OK, zrobiłem to złożenie i działa tak, jak powinno. Teraz jeszcze pytanie: chcę zrobić tak, żeby można było przeprowadzić złożenie funkcji, ale chcę samodzielnie określić krotność tego złożenia. Utworzyłem coś takiego:

(defn multicompose [f n]
	(loop [start n
		   result 0]
	       (letfn [(result [n] (f n))]
		   (if (= start 0) result (recur (dec start) result)))))

I np. chcę wywołać ((multicompose inc 3) 4) => powinienem dostać 3-krotne złożenie inc na 4, czyli (inc (inc (inc (inc 4)))) => 8
0

Nie jestem pewien co chcesz uzyskać tymi złożeniami.

(define add1(lambda(x)(+ x 1)))
(define sub1(lambda(x)(- x 1)))

(define dotimes
  (lambda(fun arg times)
    (if(= 0 times)
       arg
       (dotimes fun(fun arg)(sub1 times)))))


(dotimes add1 3 7) ;; 10

albo tak

(define dotimes
  (lambda(fun times)
    (lambda(arg)
      (if(= 0 times)
         arg
         ((dotimes fun(sub1 times))(fun arg))))))
 
((dotimes add1 3) 4) ;; 7
0
GHC napisał(a):

Nie jestem pewien co chcesz uzyskać tymi złożeniami.

(define add1(lambda(x)(+ x 1)))
(define sub1(lambda(x)(- x 1)))

(define dotimes
  (lambda(fun arg times)
    (if(= 0 times)
       arg
       (dotimes fun(fun arg)(sub1 times)))))


(dotimes add1 3 7) ;; 10

albo tak

(define dotimes
  (lambda(fun times)
    (lambda(arg)
      (if(= 0 times)
         arg
         ((dotimes fun(sub1 times))(fun arg))))))
 
((dotimes add1 3) 4) ;; 7

Trochę to zbyt skomplikowanie wygląda :) Poszedłem w tę stronę, ale brakuje mi pomysłu jak zwrócić końcowy wynik:

(defn multicompose [f x n]
	(loop [f1 f
	       f2 x
           start n]
	       (if (= start 0) ?? (recur f1 (f2 x) (dec start)))))

Za każdym wywołaniem zmniejsza się licznik start o 1 i jak osiągnie 0...to powinien zwrócić wynik n-krotnego złożenia.

1 użytkowników online, w tym zalogowanych: 0, gości: 1