Hãy xem xét biểu diễn này cho các thuật ngữ lambda được parametrized bởi các biến miễn phí của chúng. (Xem giấy tờ bằng Bellegarde và Hook 1994, Bird và Paterson 1999, Altenkirch và Reus 1999.)
data Tm a = Var a
| Tm a :$ Tm a
| Lam (Tm (Maybe a))
Bạn có thể chắc chắn làm cho này một Functor
, nắm bắt được khái niệm về đổi tên, và một Monad
chụp khái niệm thay thế.
instance Functor Tm where
fmap rho (Var a) = Var (rho a)
fmap rho (f :$ s) = fmap rho f :$ fmap rho s
fmap rho (Lam t) = Lam (fmap (fmap rho) t)
instance Monad Tm where
return = Var
Var a >>= sig = sig a
(f :$ s) >>= sig = (f >>= sig) :$ (s >>= sig)
Lam t >>= sig = Lam (t >>= maybe (Var Nothing) (fmap Just . sig))
Bây giờ xem xét đóng ngữ: đây là những cư dân của Tm Void
. Bạn có thể nhúng cụm từ đã đóng vào các cụm từ có các biến miễn phí tùy ý. Làm sao?
fmap absurd :: Tm Void -> Tm a
Hàm bắt, tất nhiên, hàm này sẽ đi qua cụm từ không chính xác. Nhưng đó là một liên lạc trung thực hơn unsafeCoerce
. Và đó là lý do tại sao vacuous
đã được thêm vào Data.Void
...
Hoặc viết một bộ đánh giá. Dưới đây là các giá trị có biến miễn phí trong b
.
data Val b
= b :$$ [Val b] -- a stuck application
| forall a. LV (a -> Val b) (Tm (Maybe a)) -- we have an incomplete environment
Tôi vừa trình bày lambdas là bao đóng. Bộ đánh giá được parametrized bởi một môi trường lập bản đồ biến miễn phí trong a
đến các giá trị trên b
.
eval :: (a -> Val b) -> Tm a -> Val b
eval g (Var a) = g a
eval g (f :$ s) = eval g f $$ eval g s where
(b :$$ vs) $$ v = b :$$ (vs ++ [v]) -- stuck application gets longer
LV g t $$ v = eval (maybe v g) t -- an applied lambda gets unstuck
eval g (Lam t) = LV g t
Bạn đã đoán.Để đánh giá một thuật ngữ khép kín tại bất kỳ mục tiêu
eval absurd :: Tm Void -> Val b
Tổng quát hơn, Void
hiếm khi được sử dụng ngày của riêng mình, nhưng rất thuận tiện khi bạn muốn tạo một tham số kiểu theo một cách mà chỉ một số loại bất khả kháng (ví dụ ở đây , sử dụng biến miễn phí trong thuật ngữ đóng). Thông thường, các loại parametrized này đi kèm với các hàm bậc cao nâng các hoạt động trên các tham số cho các hoạt động trên toàn bộ loại (ví dụ: tại đây, fmap
, >>=
, eval
). Vì vậy, bạn vượt qua absurd
làm hoạt động chung trên Void
.
Ví dụ khác, hãy tưởng tượng sử dụng Either e v
để nắm bắt các tính toán hy vọng cung cấp cho bạn v
nhưng có thể tăng ngoại lệ loại e
. Bạn có thể sử dụng phương pháp này để ghi lại nguy cơ hành vi xấu một cách thống nhất. Đối với tính toán một cách hoàn hảo cư xử rất tốt trong bối cảnh này, hãy e
là Void
, sau đó sử dụng
either absurd id :: Either Void v -> v
để chạy một cách an toàn hoặc
either absurd Right :: Either Void v -> Either e v
để nhúng các thành phần an toàn trong một thế giới không an toàn.
Ồ, và một lần cuối cùng, xử lý "không thể xảy ra". Nó xuất hiện trong việc xây dựng dây kéo chung, ở khắp mọi nơi mà con trỏ không thể.
class Differentiable f where
type D f :: * -> * -- an f with a hole
plug :: (D f x, x) -> f x -- plugging a child in the hole
newtype K a x = K a -- no children, just a label
newtype I x = I x -- one child
data (f :+: g) x = L (f x) -- choice
| R (g x)
data (f :*: g) x = f x :&: g x -- pairing
instance Differentiable (K a) where
type D (K a) = K Void -- no children, so no way to make a hole
plug (K v, x) = absurd v -- can't reinvent the label, so deny the hole!
Tôi quyết định không xóa phần còn lại, mặc dù nó không chính xác liên quan.
instance Differentiable I where
type D I = K()
plug (K(), x) = I x
instance (Differentiable f, Differentiable g) => Differentiable (f :+: g) where
type D (f :+: g) = D f :+: D g
plug (L df, x) = L (plug (df, x))
plug (R dg, x) = R (plug (dg, x))
instance (Differentiable f, Differentiable g) => Differentiable (f :*: g) where
type D (f :*: g) = (D f :*: g) :+: (f :*: D g)
plug (L (df :&: g), x) = plug (df, x) :&: g
plug (R (f :&: dg), x) = f :&: plug (dg, x)
Thực ra, có thể nó có liên quan. Nếu bạn đang cảm thấy mạo hiểm, unfinished article này cho thấy làm thế nào để sử dụng Void
để nén các đại diện của các điều khoản với các biến miễn phí
data Term f x = Var x | Con (f (Term f x)) -- the Free monad, yet again
trong bất kỳ cú pháp tạo ra một cách tự do từ một Differentiable
và Traversable
functor f
. Chúng tôi sử dụng Term f Void
để đại diện cho các khu vực không có biến số miễn phí và [D f (Term f Void)]
để đại diện cho ống đường hầm qua các khu vực mà không có biến miễn phí đến biến không bị cô lập hoặc đường giao nhau trong đường dẫn đến hai hoặc nhiều biến miễn phí. Phải kết thúc bài viết đó đôi khi.
Đối với loại không có giá trị (hoặc ít nhất, không có giá trị nói trong công ty lịch sự), Void
hữu ích đáng kể. Và absurd
là cách bạn sử dụng nó.
Tìm kiếm nhanh cho thấy hàm 'absurd' đã được sử dụng trong bài viết này đối phó với đơn nguyên' Cont': http://www.haskellforall.com/2012/12/the-continuation-monad.html – Artyom
Bạn có thể thấy 'ngớ ngẩn' là một hướng của sự đẳng cấu giữa 'Void' và' forall a. a'. –