Tôi nghĩ rằng bạn đã cạn kiệt tất cả các khả năng thú vị. Bất kỳ Monad m => m a -> m a
chức năng nào chúng tôi có thể xác định sẽ trông giống như thế này:
e :: forall m a. Monad m => m a -> m a
e u = u >>= k
where
k :: a -> m a
k = _
Đặc biệt, nếu k = return
, e = id
. Để e
không tồn tại id
, k
phải sử dụng u
theo cách không cần thiết (ví dụ: k = const u
và k = flip fmap u . const
số tiền cho hai lần thử của bạn). Tuy nhiên, trong trường hợp như vậy, các u
hiệu ứng sẽ được nhân đôi, dẫn e
đến thất bại trong việc biến thành một hình thái đơn nguyên cho một số lựa chọn của đơn nguyên m
. Điều đó là như vậy, hình thái đơn nguyên duy nhất đa hình trong đơn nguyên là id
.
Hãy làm cho lập luận rõ ràng hơn.
Để rõ ràng, tôi sẽ chuyển sang join
/ return
/ fmap
thuyết trình một lát. Chúng tôi muốn thực hiện:
e :: forall m a. Monad m => m a -> m a
e u = _
Những gì chúng ta có thể điền vào phía bên tay phải với? Lựa chọn rõ ràng nhất là u
. Chính nó, điều đó có nghĩa là e = id
, điều đó không có vẻ thú vị. Tuy nhiên, vì chúng ta cũng có join
, return
và fmap
, có tùy chọn suy luận theo quy nạp, u
như trường hợp cơ sở. Nói rằng chúng tôi có một số v :: m a
, được xây dựng bằng cách sử dụng các phương tiện chúng tôi có trong tay. Ngoài v
ra, chúng ta có các khả năng sau:
join (return v)
, đó là v
và do đó không cho chúng ta biết bất cứ điều gì mới;
join (fmap return v)
, đó là v
tốt; và
join (fmap (\x -> fmap (f x) w) v)
, đối với một số khác w :: m a
được xây dựng theo quy tắc của chúng tôi, và một số f :: a -> a -> a
. (Thêm m
lớp để các loại f
, như trong a -> a -> m a
, và thêm join
s để loại bỏ chúng sẽ không dẫn bất cứ nơi nào, như sau đó chúng ta sẽ phải thể hiện xuất xứ của những lớp, và điều cuối cùng sẽ làm giảm các trường hợp khác).
Trường hợp thú vị duy nhất là # 3. Tại thời điểm này, tôi sẽ đi một lối tắt:
join (fmap (\x -> fmap (f x) w) v)
= v >>= \x -> fmap (f x) w
= f <$> v <*> w
Bất kỳ phi u
phía bên tay phải, do đó, có thể được thể hiện dưới dạng f <$> v <*> w
, với v
và w
là một trong hai u
hoặc lặp đi lặp lại hơn nữa của mô hình này, cuối cùng đạt u
s ở lá. Tuy nhiên, các biểu thức áp dụng của loại này có dạng chính tắc, có được bằng cách sử dụng các luật áp dụng để liên kết lại tất cả các cách sử dụng (<*>)
bên trái, trong trường hợp này phải như thế này ...
c <$> u <*> ... <*> u
... Với dấu chấm lửng đứng ở vị trí 0 hoặc nhiều lần xuất hiện khác của khoảng u
cách <*>
và c
là một a -> ... -> a -> a
chức năng của sự tự nhiên thích hợp. Do a
là đa hình hoàn toàn, c
nên, theo tham số, phải là một const
hàm giống như một số đối số chọn một trong các đối số của nó. Điều đó là như vậy, bất kỳ biểu hiện như vậy có thể được viết lại về (<*)
và (*>)
...
u *> ... <* u
... Với dấu chấm lửng đứng bằng 0 hoặc nhiều lần xuất hiện u
cách nhau bởi một trong hai *>
hoặc <*
, không có *>
bên phải của a <*
.
Quay trở lại bắt đầu, tất cả các id
triển khai không phải là ứng cử viên phải trông như thế này:
e u = u *> ... <* u
Chúng tôi cũng muốn e
trở thành một hình thái đơn nguyên. Kết quả là, nó cũng phải là một hình thái ứng dụng. Đặc biệt:
-- (*>) = (>>) = \u v -> u >>= \_ -> v
e (u *> v) = e u *> e v
Đó là:
(u *> v) *> ... <* (u >* v) = (u *> ... <* u) *> (v *> ... <* v)
Bây giờ chúng ta có một con đường rõ ràng hướng tới một ví dụ mẫu. Nếu chúng ta sử dụng các luật áp dụng để chuyển đổi cả hai mặt sang dạng chính tắc, chúng ta sẽ (vẫn) kết thúc với các u
s và s xen kẽ v
ở phía bên trái và với tất cả các v
s sau tất cả các u
s ở phía bên tay phải. Điều đó có nghĩa là tài sản sẽ không giữ cho các đơn vị như IO
, State
hoặc Writer
, bất kể có bao nhiêu (*>)
và (<*)
có e
, hoặc chính xác giá trị nào được chọn bởi các const
hàm giống như ở hai bên. Một bản demo nhanh:
GHCi> e u = u *> u <* u -- Canonical form: const const <$> u <*> u <*> u
GHCi> e (print 1 *> print 2)
1
2
1
2
1
2
GHCi> e (print 1) *> e (print 2)
1
1
1
2
2
2
u
sẽ nhất thiết phải được nhân đôi trừ khie = id
? (Chúng tôi cũng có thể viếte u = do _ <- u; _ <- u; _ <- u; u
và kết hợp thêmu
-effects.) Làm thế nào chúng ta có thể mô tả toán học rằng "một giá trị monadicp :: m a
có nhiều hiệu ứng sao chép từu :: m a
? Và sau đó, làm thế nào chúng ta có thể chứng minh rằng nhân đôi (triplicated, vv)u
-effects nhất thiết dẫn đến hành vi vi phạm luật hình thái đơn nguyên?