Tôi đang viết một khuôn khổ, trong đó chức năng chính hỏi người dùng về chức năng loại a -> [b]
.Có cách nào "chuẩn" để sử dụng tính tương đương của Reader và chức năng bình thường không?
Tuy nhiên, bởi vì chức năng đó có thể khá phức tạp, thực hiện của nó có thể thường trông như thế này:
fn a = extractPartOfAAndConvert a ++ extractAnotherPartofAAndConvert a
Đó là lý do tại sao tôi figured sử dụng Reader
có thể là một, ý tưởng thành ngữ tốt đẹp để đấu tranh đó. Tuy nhiên, đồng thời tôi nhận ra rằng một số người có thể không muốn sử dụng một đơn nguyên.
Trong khi thử nghiệm, tôi đã chế tác giải pháp này:
class Iso a b where
isoFrom :: a -> b
isoTo :: b -> a
instance Iso a a where
isoFrom = id
isoTo = id
instance Iso (a -> b) (Reader a b) where
isoFrom f = reader f
isoTo m = runReader m
do đó cho phép tôi làm:
testCallback :: MyState -> Callback -> MyState
testCallback myState cb = cb myState
-- The important signature
testCallbackGeneric :: Iso Callback a => MyState -> a -> MyState
testCallbackGeneric myState cb = (isoTo cb) myState
callbackFunction :: Callback
callbackFunction s = s + 10
callbackMonad :: Reader MyState MyState
callbackMonad = do
x <- ask
return $ x - 10
-----------
let myStateA = testCallback myState callbackFunction
-- let myStateB = testCallback myState callbackMonad -- won't work, obviously
let myStateC = testCallbackGeneric myState callbackFunction
let myStateD = testCallbackGeneric myState callbackMonad
Tuy nhiên, tôi cảm thấy rất giống tôi reinventing the wheel.
Có cách nào để thể hiện sự tương đương của Reader để dễ dàng viết các chức năng chung như vậy mà không cần phải tạo lớp của riêng mình không?
Một điều nữa là cho dù đó là thực sự có lợi ích để cung cấp chữ ký phức tạp như vậy, nơi người dùng có thể dễ dàng chuyển sang preferrable cách, giống như trường hợp. Tôi nghĩ rằng không có lý do tại sao mà boilerplate không nên tránh/lấy ra khỏi người sử dụng. –
Bạn có thể sử dụng ràng buộc 'MonadReader', mà đã tồn tại một cá thể cho các hàm. Nếu bạn viết 'f = do {a <- ask; trả về $ 2 * a + 3 * a} ', sau đó bạn có thể sử dụng nó như một hàm như' f 1 == 5' hoặc trong bất kỳ hàm 'Reader' nào trong đó' f :: MonadReader Int m => m Int'. Điều này có thể chuyên về 'Int -> Int' hoặc' Int 'Int'. – bheklilr
@ bheklilr * mà đã tồn tại một thể hiện cho các chức năng. * NÀY. Đây là những gì tôi đã mất tích toàn bộ thời gian! Viết câu trả lời này để tôi có thể upvote nó! :) (và có 'Callback' chỉ là' MyState -> MyState', và 'MyState ~ Int') –