2010-11-11 12 views
8

Jeśli mam instancji Bifunctor[A,A] bf, funkcja f : A => A i wartość Booleanp:Wywoływanie funkcji na „stronie” o Bifunctor zależnej od wartości logicznej

def calc[A, F[_,_]: Bifunctor](p: Boolean, bf: F[A, A], f: A => A): F[A, A] = { 
    val BF = implicitly[Bifunctor[F]] 
    BF.bimap(bf, (a : A) => if (p) f(a) else a, (a : A) => if (!p) f(a) else a) 
} 

Jak mogę umieścić to bardziej zwięźle (i ekspresyjnie)? Zasadniczo próbuję wywołać funkcję na stronie bifunctor (np. Tuple2) w zależności od niektórych predykatów. Jeżeli orzeczenie to prawda, chcę mapować LHS i RHS, czy to fałszywy

val t2 = (1, 2) 
def add4 = (_ : Int) + 4 
calc(true, t2, add4) //should be (5,2) 
calc(false, t2, add4) //should be (1,6) 


Zważywszy, że chcę użyć krotki (w przeciwieństwie do bardziej ogólnego Bifunctor), wydaje mi się, aby móc używać arrows następująco:

def calc[A](p: Boolean, bf: (A, A), f: A => A): (A, A) 
    = (if (p) f.first[A] else f.second[A]) apply bf 

Odpowiedz

4

Nie aż tak dużo ładniejszy:

def calc[A, F[_,_]:Bifunctor](p: Boolean, bf: F[A, A], f: A => A): F[A, A] = 
    (if (p) (bf :-> (_: A => A)) else ((_:A => A) <-: bf))(f) 

trochę ładniejszy:

def cond[A:Zero](b: Boolean, a: A) = if (b) a else mzero 

def calc[A, F[_,_]:Bifunctor](p: Boolean, bf: F[A, A], f: Endo[A]): F[A, A] = 
    cond(p, f) <-: bf :-> cond(!p, f) 

Niektóre Haskell, tylko zazdrość język:

calc p = if p then first else second 
+0

Problem polega na tym, że piszę to * inline * (tj. Nie chcę zadeklarować dodatkowej metody), więc nie chcę dwa razy pisać 'bf', ponieważ jest (w fakt) wynik wywołania metody. Rozwiązanie ze strzałkami, które znalazłem, działa naprawdę dobrze –

+0

Powinienem powiedzieć, że chcę mieć dostęp tylko do 'p' raz i tak –

+0

Dla rozwiązania haskell, czy nie musisz stosować wyników do bifunektora? Czy to jest ukryte? (Nie wiem, haskell) –

0

Edit: stałe powrócić (A,A) zamiast A

Może jestem brakuje czegoś, ale czy nie do tego służą zmienne tymczasowe? Z regularnym krotki Scala:

Some(bf).map(x => if (p) x.copy(_1 = f(x._1)) else x.copy(_2 = f(x._2))).get 

lub

{ val (l,r) = bf; if (p) (f(l),r) else (l,f(r)) } 
+0

Czy możesz to zrobić z dowolnymi bifunktorami? – Apocalisp

+0

@Apocalisp - Prawdopodobnie nie (nie miałem okazji używać arbitralnych bifunktorów, więc nie jestem dobrze zorientowany w ich właściwościach), ale wychodziłem z części "dane, że chcę użyć krotek". pytanie. –

+0

Wystarczająco fair. Bifunktory mają jedną metodę: def bimap [A, B, C, D] (k: F [A, B], f: A => C, g: B => D): F [C, D] ', zaspokajanie niektórych oczywistych praw (podanych przez parametryczność). – Apocalisp

0

Czy to wariacja na Apocalisp's solution pracy?

def calc[A, F[_,_]:Bifunctor](p: Boolean, bf: F[A, A], f: A => A): F[A, A] = 
    (if (p) ((_: F[A,A]) :-> f) else (f <-: (_: F[A,A])))(bf) 

Uwaga: Nie testowałem tego z scalaz.

Powiązane problemy