2013-05-14 27 views
7

Tôi đang gặp một chút khó khăn với máy biến áp đơn dòng tại thời điểm này. Tôi đang xác định một vài quan hệ không xác định khác nhau, sử dụng biến thế. Thật không may, tôi đang gặp khó khăn trong việc hiểu cách dịch từ một mô hình hiệu quả sang mô hình hiệu quả khác.Chuyển đổi dưới Máy biến áp

Giả sử các mối quan hệ này là "foo" và "bar". Giả sử rằng "foo" liên quan đến As và Bs thành Cs; giả sử "bar" liên quan Bs và Cs với Ds. Chúng tôi sẽ xác định "thanh" theo "foo". Để làm cho các vấn đề trở nên thú vị hơn, việc tính toán các mối quan hệ này sẽ thất bại theo nhiều cách khác nhau. (Kể từ khi mối quan hệ thanh phụ thuộc vào mối quan hệ foo, các trường hợp thất bại của nó là một superset). Vì vậy, tôi đưa ra các định nghĩa loại sau đây:

data FooFailure = FooFailure String 
data BarFailure = BarSpecificFailure | BarFooFailure FooFailure 
type FooM = ListT (EitherT FooFailure (Reader Context)) 
type BarM = ListT (EitherT BarFailure (Reader Context)) 

sau đó tôi mong chờ để có thể viết các mối quan hệ với các chữ ký chức năng sau :

foo :: A -> B -> FooM C 
bar :: B -> C -> BarM D 

Vấn đề của tôi là khi viết định nghĩa cho "bar", tôi cần có thể nhận lỗi từ mối quan hệ "foo" và đại diện cho chúng trong không gian "bar". Vì vậy, tôi sẽ tốt với một chức năng của hình thức

convert :: (e -> e') -> ListT (EitherT e (Reader Context) a 
        -> ListT (EitherT e' (Reader Context) a 

tôi thậm chí có thể viết rằng con thú nhỏ bằng cách chạy ListT, lập bản đồ trên EitherT, và sau đó reassembling ListT (vì nó sẽ xảy ra rằng m [a] có thể được chuyển đổi thành ma ListT). Nhưng điều này có vẻ ... lộn xộn.

Có lý do chính đáng là tôi không thể chỉ chạy máy biến áp, thực hiện một số công cụ dưới nó và nói chung "đặt lại"; biến áp tôi chạy có thể có hiệu ứng và tôi không thể hoàn tác chúng một cách kỳ diệu. Nhưng có một số cách mà tôi có thể nâng một chức năng chỉ đủ xa vào một ngăn xếp biến áp để làm một số công việc cho tôi vì vậy tôi không phải viết các chức năng convert được hiển thị ở trên?

Trả lời

3

Tôi nghĩ rằng chuyển đổi là một câu trả lời tốt, và sử dụng Control.Monad.MorphControl.Monad.Trans.Either nó (hầu như) thực sự đơn giản để viết:

convert :: (Monad m, Functor m, MFunctor t) 
      => (e -> e') 
      -> t (EitherT e m) b -> t (EitherT e' m) b 
convert f = hoist (bimapEitherT f id) 

vấn đề nhẹ là ListT không phải là một thể hiện của MFunctor. Tôi nghĩ rằng đây là tác giả tẩy chay ListT vì nó doesn't follow the monad transformer laws mặc dù bởi vì nó dễ dàng để viết một loại kiểm tra dụ

instance MFunctor ListT where hoist nat (ListT mas) = ListT (nat mas) 

Dù sao, nói chung là hãy nhìn vào Control.Monad.Morph để đối phó với biến đổi tự nhiên trên (một phần) ngăn xếp biến áp. Tôi muốn nói rằng phù hợp với định nghĩa của nâng một chức năng "vừa đủ" vào một ngăn xếp.

+1

Vâng, tôi đang tẩy chay ListT. Sử dụng 'pipe' cho một ListT đúng. Ngoài ra, bạn có thể sử dụng 'fmapLT' từ gói lỗi để sửa đổi giá trị bên trái. –

+0

Tôi đang tìm 'fmapLT' ...! Nhưng tôi có thể thề là 'hoặc' và không hoogle nó. –

+0

Tuyệt vời; cảm ơn cả hai người. Đây chính là điều tôi đang thắc mắc. :) – tvynr

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