Tôi không nghĩ rằng định nghĩa cho SbT
là những gì bạn muốn. Điều đó xác định thành phần functor và giả sử tham số m
là Functor
hoặc Applicative
, điều này sẽ giữ nguyên các thuộc tính đó. Nhưng thành phần như vậy không, nói chung, tạo ra một đơn nguyên mới ra khỏi hai người khác. Xem this question để biết thêm về chủ đề đó.
Vì vậy, cách làm bạn tạo biến áp đơn lẻ bạn muốn, sau đó? Trong khi các monads không soạn trực tiếp, các trình biến đổi đơn lẻ có thể được sáng tác. Vì vậy, để xây dựng một biến mới ra khỏi những cái hiện có, về cơ bản bạn chỉ muốn đặt tên cho thành phần đó. Điều này khác với newtype
bạn có bởi vì bạn đang áp dụng trực tiếp m
thay vì chuyển nó vào ngăn máy biến áp. Một điều cần lưu ý về việc xác định biến thế đơn nguyên là chúng nhất thiết phải làm việc "ngược" theo những cách nhất định - khi bạn áp dụng máy biến áp tổng hợp thành một đơn nguyên, biến áp "trong cùng" sẽ là vết nứt đầu tiên ở đó, và đơn nguyên được biến đổi mà nó tạo ra là biến thế tiếp theo được làm việc với, & c. Lưu ý rằng điều này không khác với thứ tự bạn nhận được khi áp dụng một hàm được soạn thảo cho một đối số, ví dụ: (f . g . h) x
đặt đối số cho h
trước tiên, mặc dù f
là hàm "đầu tiên" trong bố cục.
Được rồi, vì vậy biến áp tổng hợp của bạn cần phải lấy đơn nguyên nó được áp dụng đến và vượt qua nó để máy biến áp trong cùng, đó là, uhm .... oops, chỉ ra rằng SB
là đã áp dụng cho một đơn nguyên. Không có gì lạ khi nó không hoạt động. Chúng tôi sẽ cần phải loại bỏ điều đó, trước tiên. Nó đâu rồi? Không phải State
- chúng tôi có thể xóa điều đó, nhưng chúng tôi không muốn, bởi vì đó là một phần của những gì bạn muốn. Hmm, nhưng chờ đợi - State
được định nghĩa là gì? Oh yeah:
type State s = StateT s Identity
Aha, chúng tôi đi. Hãy lấy số Identity
ra khỏi đó.Chúng tôi đi từ định nghĩa hiện tại của bạn:
type SB i a = ReaderT (AlgRO i) (State (AlgState i)) a
Đối với hình thức tương đương:
type SB i a = ReaderT (AlgRO i) (StateT (AlgState i) Identity) a
Sau đó, chúng tôi đá bum lười biếng ra:
type SB' i m a = ReaderT (AlgRO i) (StateT (AlgState i) m) a
type SB i a = SB' i Identity a
Nhưng bây giờ SB'
vẻ nghi ngờ như một biến đơn nguyên định nghĩa, và với lý do chính đáng, bởi vì nó là. Vì vậy, chúng tôi tái tạo newtype
wrapper, và quăng một vài trường hợp ngoài kia:
newtype SbT i m a = SbT { getSB :: ReaderT (AlgRO i) (StateT (AlgState i) m) a }
instance (Functor m) => Functor (SbT i m) where
fmap f (SbT sb) = SbT (fmap f sb)
instance (Monad m) => Monad (SbT i m) where
return x = SbT (return x)
SbT m >>= k = SbT (m >>= (getSB . k))
instance MonadTrans (SbT i) where
lift = SbT . lift . lift
runSbT :: SbT i m a -> AlgRO i -> AlgState i -> m (a, AlgState t)
runSbT (SbT m) e s = runStateT (runReaderT m e) s
Một vài điều cần lưu ý: Các runSbT
chức năng ở đây không phải là accessor lĩnh vực, mà là một sáng tác "chạy" chức năng cho mỗi biến áp trong ngăn xếp mà chúng ta biết. Tương tự, chức năng lift
phải nâng một lần cho hai máy biến áp bên trong, sau đó thêm lớp phủ newtype
cuối cùng. Cả hai đều làm cho nó hoạt động như một biến áp đơn lẻ, che giấu thực tế rằng nó thực sự là một hỗn hợp.
Nếu bạn muốn, bạn nên viết đơn giản cho các trường hợp MonadReader
và MonadState
bằng cách nâng các phiên bản cho máy biến áp đã soạn.
Điều đó sẽ làm điều đó. Cảm ơn! – dsign