Lưu ý rằng bạn có thể chuỗi bất kỳ số nào là <*>
, để có được chức năng của biểu mẫu
f (a0 -> .. -> an) -> (f a0 -> .. -> f an)
Nếu chúng tôi có loại a0 -> .. -> an
và f a0 -> .. -> f an
, chúng tôi có thể tính f
từ điều này. Chúng tôi có thể mã hóa mối quan hệ này, và loại chung nhất, như sau
class Lift a f b | a b -> f where
lift' :: f a -> b
Như bạn có thể mong đợi, các "trường hợp đệ quy" dụ sẽ chỉ cần áp dụng <*>
một lần, sau đó recurse:
instance (a ~ a', f' ~ f, Lift as f rs, Applicative f)
=> Lift (a -> as) f (f' a' -> rs) where
lift' f a = lift' $ f <*> a
Các cơ sở trường hợp là khi không có thêm chức năng. Vì bạn không thể thực sự khẳng định "a
không phải là một loại chức năng", điều này phụ thuộc vào trường hợp chồng chéo:
instance (f a ~ b) => Lift a f b where
lift' = id
Do GHCs quy tắc lựa chọn Ví dụ, trường hợp đệ quy sẽ luôn luôn được lựa chọn, nếu có thể.
Sau đó các chức năng bạn muốn là lift' . pure
:
lift :: (Lift a f b, Applicative f) => a -> b
lift x = lift' (pure x)
Đây là nơi mà phụ thuộc chức năng trên Lift
trở nên rất quan trọng. Vì f
chỉ được đề cập trong ngữ cảnh, chức năng này sẽ bị đánh máy sai trừ khi chúng tôi có thể xác định f
chỉ biết a
và b
(xuất hiện ở bên phải của =>
).
Điều này đòi hỏi nhiều phần mở rộng:
{-# LANGUAGE
OverlappingInstances
, MultiParamTypeClasses
, UndecidableInstances
, FunctionalDependencies
, ScopedTypeVariables
, TypeFamilies
, FlexibleInstances
#-}
và, như thường lệ với các chức năng variadic trong Haskell, thường là cách duy nhất để chọn một thể hiện là để cho một chữ ký kiểu tường minh.
lift (\x y z -> x * y + z) readLn readLn readLn :: IO Int
Con đường tôi đã viết nó, GHC sẽ vui vẻ chấp nhận lift
đó là đa hình trong lập luận để f
(nhưng không f
chính nó).
lift (+) [1..5] [3..5] :: (Enum a, Num a) => [a]
Đôi khi bối cảnh đủ để suy ra loại chính xác. Lưu ý rằng loại đối số là một lần nữa đa hình.
main = lift (\x y z -> x * y + z) readLn readLn readLn >>= print
Tính đến GHC> = 7.10, OverlappingInstances
đã bị phản đối và trình biên dịch sẽ phát hành một cảnh báo. Nó có thể sẽ được gỡ bỏ trong một số phiên bản sau này. Điều này có thể được sửa chữa bằng cách loại bỏ OverlappingInstances
từ {-# LANGUAGE .. #-}
pragma và thay đổi Ví dụ 2 đến
instance {-# OVERLAPS #-} (f a ~ b) => Lift a f b where
Loại bạn đang cố gắng nâng _to_? Tôi thấy '<*>' trong mã, nhưng tôi không thấy bất kỳ đề cập nào về 'Áp dụng' trong các chữ ký kiểu ... Dù bằng cách nào, tôi nghi ngờ trường hợp' Nâng a' sẽ là một vấn đề, vì nó trùng lặp với mọi thể hiện có thể khác (bao gồm 'Nâng (a -> r)'). – MathematicalOrchid
Nevermind mã của tôi, tôi đã thử một tấn những thứ (có lẽ là vô nghĩa), chỉ cần đăng một số ảnh chụp ngẫu nhiên vì lợi ích của nó. Tôi thực sự bối rối với khái niệm này, bởi vì, ví dụ, 'lift (pure (+)) (Just 1) (Chỉ 2)' - ở đây, '(pure (+))' có một kiểu khác với 'Just 1 ', nhưng cấu trúc được cung cấp là hardcoded cho một kiểu' Integer' ... Tôi cũng cần một cách để mã hóa một cá thể cho "bất kỳ kiểu nào không phải là một hàm", như là một điều kiện chấm dứt cho việc loại bỏ kiểu. – MaiaVictor