2011-10-03 10 views
5

Cho một chữ ký như thế này một hoặc that one:Chuỗi coi là một monoid

def foo[A, F[_]](implicit mon: Monoid[F[A]], pr: Pure[F]): F[A] 

Giả sử A là Char, là có một cách để có được một String thay vì một List[Char]?

String không có tham số loại, vì vậy tôi cho rằng không thể thực hiện được. Lựa chọn tốt nhất tiếp theo là gì? Ngay bây giờ, tôi sử dụng mkString trên kết quả, nhưng điều đó không cảm thấy tối ưu.

Tôi nghĩ String là một monoid với zero""thêm+ ...

+0

Tại sao bạn cần Monoid [F [A]] thay vì chỉ Monoid [F]? – CheatEx

+0

@CheatEx, trong trường hợp này, tôi không phải là người viết 'foo', tôi chỉ là người gọi. – huynhjl

Trả lời

7

Có thể thuyết phục Chuỗi giả mạo thành loại cao cấp hơn và do đó cho phép các chức năng ở dạng foo được áp dụng. Tuy nhiên, suy luận kiểu Scala không phải là hiện lên đến công việc của Suy luận foo 's đối số loại, vì vậy bạn sẽ phải cung cấp cho họ một cách rõ ràng,

// Assuming the the definitions of Pure and Monoid from Scalaz 

type ConstString = { 
    type λ[X] = String 
} 

implicit def StringPure = new Pure[ConstString#λ] { 
    def pure[A](a: => A) = a.toString 
} 

val sm = implicitly[Monoid[String]] 
val sp = implicitly[Pure[ConstString#λ]] 
val f : String = foo[Char, ConstString#λ](sm, sp) // OK 

Lưu ý rằng Char kiểu lập luận để foo là không sử dụng và có thể là bất cứ điều gì, nhưng phải là một cái gì đó: trong trường hợp này là Char là sự lựa chọn tự nhiên, nhưng Nothing hoặc Any cũng sẽ hoạt động.

Lưu ý rằng giải pháp này giao dịch trên các đặc điểm đặc biệt của String: giá trị của tất cả các loại có thể chuyển đổi thành String s để pure[A](a : => A) : String có thể triển khai được cho tất cả các loại A. Việc sao chép thành ngữ này cho các loại khác ngoài String rất có thể sẽ phải khai thác một số cơ chế để triển khai các trường hợp loại cụ thể trong phần nội dung của pure (ví dụ: kết hợp mẫu của một số loại).

+2

Nhưng 'ngầm [Pure [ConstString # λ]]. Thuần túy ('a')' sẽ trả về chuỗi rỗng, vì vậy điều này không thực sự được sử dụng nhiều. Là nó? –

+0

Chắc chắn, bạn cần định nghĩa khác về 'Pure [ConstString # λ]' để thực hiện bất kỳ công việc hữu ích nào. Trả lời chỉnh sửa để phản ánh điều đó. –

+0

Tôi nghĩ tôi đã thấy một Kestrel! –

0

phân tích của bạn, loại hệ thống scala sẽ từ chối String như không phải là một "loại kinded cao" * -> * đúng. Đó là, các kiểu String là không thể chuyển nhượng để F[_] cho bất kỳ F. Bạn có thể thử (tôi đã không kiểm tra này) chuyển đổi tiềm ẩn ...

def foo[A, F[_], That](implicit mon: Monoid[F[A]], pr: Pure[F], FA_Is_That: F[A] <%< That) 

... nhưng điều này sẽ không thể là tôi hữu ích nghi ngờ bởi vì bạn sẽ phải cung cấp các chuyển đổi riêng biệt của riêng bạn khi cần thiết nhưng cũng bởi vì hiệu suất sẽ là khủng khiếp, giả sử đây là một phần nóng của mã.

Hoặc, sử dụng thư viện tiêu chuẩn, bạn có thể sử dụng các máy móc CanBuildFrom nhưng nó xa rõ ràng như thế nào độc đáo này sẽ kết hợp với typeclasses scalaz kiểu.

def foo[A, F[_], That](implicit mon: Monoid[F[A]], pr: Pure[F], b: CanBuildFrom[A, F[A], That]): That 

Trong cơ thể của phương pháp này, tất nhiên, bạn sẽ cần phải sử dụng trình tạo để xây dựng các giá trị trả về, như trái ngược với/typeclasses tinh khiết monoid, khiến họ phần nào không cần thiết, tôi nghi ngờ.

6

Giải pháp tốt nhất mà tôi có thể nghĩ đến là xác định chuyển đổi ẩn từ List[Char] thành String.