2010-11-11 14 views
8

Nếu tôi có một thể hiện của Bifunctor[A,A] bf, một chức năng f : A => A và một giá trị Booleanp:Gọi một hàm trên một "mặt" của một Bifunctor phụ thuộc vào giá trị của một boolean

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) 
} 

Làm thế nào tôi có thể đặt điều này chính xác hơn (và rõ ràng)? Về cơ bản, tôi đang cố gọi hàm ở bên cạnh một số bifunctor (ví dụ: Tuple2) phụ thuộc vào một số biến vị ngữ. Nếu vị là đúng, tôi muốn để lập bản đồ LHS và RHS nếu nó sai

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


Cho rằng tôi muốn sử dụng các bộ (như trái ngược với khái quát hơn Bifunctor), tôi dường như có thể sử dụng arrows như sau:

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

Trả lời

4

Không phải tất cả rằng có rất nhiều đẹp hơn:

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) 

Một chút đẹp hơn:

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) 

Một số Haskell, chỉ dành riêng cho những ghen tị ngôn ngữ:

calc p = if p then first else second 
+0

Vấn đề là tôi đang viết nội dung * inline * (nghĩa là tôi không muốn khai báo phương thức bổ sung), vì vậy tôi không muốn phải viết 'bf' hai lần, vì nó là (trong thực tế) kết quả của một lời gọi phương thức. Các giải pháp mũi tên tôi tìm thấy thực sự hoạt động thực sự tốt –

+0

Tôi nên nói rằng tôi cũng muốn chỉ truy cập 'p' một lần là tốt –

+0

Đối với giải pháp haskell, bạn không cần phải áp dụng kết quả cho bifunctor? Hoặc là tiềm ẩn? (Tôi không biết haskell) –

0

Edit: cố định để trở (A,A) thay vì A

Có lẽ tôi đang thiếu cái gì, nhưng không phải là những biến tạm thời này là gì? Với Scala tuple thường xuyên:

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

hoặc

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

bạn có thể làm điều đó với bifunctors tùy ý? – Apocalisp

+0

@Apocalisp - Có lẽ không phải (tôi chưa từng có dịp sử dụng bifunctors tùy ý vì vậy tôi không thông thạo tài sản của họ), nhưng tôi đã đi ra khỏi "cho rằng tôi muốn sử dụng tuples" một phần của câu hỏi. –

+0

Đủ công bằng. Bifunctors chỉ có một phương thức 'def bimap [A, B, C, D] (k: F [A, B], f: A => C, g: B => D): F [C, D]', đáp ứng một số luật rõ ràng (được đưa ra bởi tham số). – Apocalisp

0

Liệu sự thay đổi này trên Apocalisp's solution làm việc?

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) 

Lưu ý: Tôi không kiểm tra điều này với scalaz.

Các vấn đề liên quan