Có, nó có thể được thực hiện ở một mức độ giới hạn.
Nhưng trước tiên chúng ta cần
{-# LANGUAGE Rank2Types #-}
Hãy xác định
data M a b = M { name :: Int -> String -> String, eval :: a -> b }
tôi thêm cấu trúc cho tên của bạn để tôi có thể nhận được hỗ trợ chương trình đẹp hơn. ;)
Sau đó, cho phép xác định một lớp:
class Magic m where
magic :: M a b -> m a b
instance Magic M where
magic = id
instance Magic (->) where
magic (M _ f) = f
Bây giờ, hãy xem xét loại:
type MyFunc a b = forall m. Magic m => m a b
Kiểu kết quả của magic
là một trong hai (a -> b)
hoặc một M a b
.
Vì vậy, nó có thể được sử dụng như một thành viên của MyFunc
. Bây giờ, loại này hơi không thỏa mãn, bởi vì bạn không thể tạo các trường hợp gửi đi, nhưng điều đó có nghĩa là
inc :: MyFunc Int Int
inc = magic (M (const (showString "inc")) (+1))
test :: Int
test = inc 1
chỉ hoạt động tốt.
Chúng tôi thậm chí có thể tạo ra một cách khá hay để hiển thị chúng. Mặc dù chúng tôi không thể sử dụng hiển thị trên MyFunc
, chúng tôi có thể xác định nó cho M
.
instance Show (M a b) where
showsPrec d (M s _) = s d
Sau đó, chúng ta có thể thực hiện một chức năng chúng ta có thể áp dụng đối với M a b
(và bằng cách mở rộng bất kỳ MyFunc
) để lấy ra một M a b
.
m :: M a b -> M a b
m = id
và chúng ta có thể định nghĩa một combinator đặc biệt để hiển thị MyFunc
s:
showM :: MyFunc a b -> String
showM f = show (m f)
Sau đó chúng ta có thể chơi. Chúng tôi có thể xác định các chế phẩm của MyFunc
s.
infixr 9 .#
(.#) :: MyFunc b c -> MyFunc a b -> MyFunc a c
f .# g = magic (M
(\d -> showParen (d > 9) $ showsPrec 10 (m f) .
showString " . " .
showsPrec 9 (m g))
(f . g))
inc2 :: MyFunc Int Int
inc2 = inc .# inc
test2 :: Int
test2 = inc2 1
bar, baz :: String
bar = showM inc
baz = showM inc2
Và bởi vì tôi đã cung cấp đủ cấu trúc cho tên, chúng tôi thậm chí có được dấu ngoặc đơn chính xác cho các tác phẩm phức tạp hơn mà không cần dấu ngoặc đơn.
*Main> showM $ inc2 .# inc
"(inc . inc) . inc"
*Main> showM $ inc .# inc2
"inc . inc . inc"
Nhưng hãy nhớ, bạn sẽ không thể xác định bất kỳ trường hợp cho MyFunc
, vì nó chỉ có thể là một type
, và không phải là một newtype
. Để xác định các cá thể, bạn sẽ phải xác định chúng trên M
và sau đó sử dụng m
để chuyển đổi thành loại đó để công văn tiềm ẩn có loại để lấy.
Do loại xếp hạng 2, nếu bạn sử dụng rất nhiều trong ngữ cảnh cục bộ, bạn cũng có thể muốn bật NoMonoLocalBinds
và/hoặc NoMonomorphismRestriction
.
Đây là loại đáng sợ. Tôi thích nó. –