Pertimbangkan representasi ini untuk istilah lambda yang diparameterisasi oleh variabel bebasnya. (Lihat makalah oleh Bellegarde dan Hook 1994, Bird dan Paterson 1999, Altenkirch dan Reus 1999.)
data Tm a = Var a
| Tm a :$ Tm a
| Lam (Tm (Maybe a))
Anda pasti bisa membuat ini menjadi Functor
, menangkap gagasan penggantian nama, dan Monad
menangkap gagasan substitusi.
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))
Sekarang pertimbangkan istilah tertutup : ini adalah penghuni Tm Void
. Anda harus dapat menyematkan istilah tertutup ke dalam istilah dengan variabel bebas arbitrer. Bagaimana?
fmap absurd :: Tm Void -> Tm a
Tangkapannya, tentu saja, adalah bahwa fungsi ini akan melintasi istilah tanpa melakukan apa pun. Tapi itu sentuhan yang lebih jujur daripada unsafeCoerce
. Dan itulah mengapa vacuous
ditambahkan keData.Void
...
Atau tulis seorang evaluator. Berikut adalah nilai dengan variabel bebas di b
.
data Val b
= b :$$ [Val b] -- a stuck application
| forall a. LV (a -> Val b) (Tm (Maybe a)) -- we have an incomplete environment
Saya baru saja mewakili lambda sebagai penutup. Evaluator diparameterisasi oleh lingkungan yang memetakan variabel bebas a
ke nilai di atas 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
Anda dapat menebaknya. Untuk mengevaluasi istilah tertutup pada target apa pun
eval absurd :: Tm Void -> Val b
Lebih umum, Void
jarang digunakan sendiri, tetapi berguna ketika Anda ingin membuat contoh parameter tipe dengan cara yang menunjukkan semacam ketidakmungkinan (misalnya, di sini, menggunakan variabel bebas dalam istilah tertutup). Seringkali tipe parametrized ini hadir dengan operasi pengangkatan fungsi tingkat tinggi pada parameter ke operasi pada keseluruhan tipe (misalnya, di sini,fmap
, >>=
, eval
). Jadi Anda lulus absurd
sebagai operasi tujuan umum Void
.
Untuk contoh lain, bayangkan menggunakan Either e v
untuk menangkap komputasi yang diharapkan memberi Anda v
tetapi mungkin menimbulkan pengecualian jenise
. Anda mungkin menggunakan pendekatan ini untuk mendokumentasikan risiko perilaku buruk secara seragam. Untuk sempurna berperilaku baik perhitungan dalam pengaturan ini, mengambil e
menjadi Void
, maka penggunaan
either absurd id :: Either Void v -> v
untuk berlari dengan aman atau
either absurd Right :: Either Void v -> Either e v
untuk menanamkan komponen yang aman di dunia yang tidak aman.
Oh, dan hore terakhir, menangani "tidak bisa terjadi". Ini muncul dalam konstruksi ritsleting umum, di mana pun kursor tidak bisa berada.
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!
Saya memutuskan untuk tidak menghapus sisanya, meskipun itu tidak terlalu relevan.
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)
Sebenarnya, mungkin itu relevan. Jika Anda suka berpetualang, artikel yang belum selesai ini menunjukkan cara menggunakan Void
untuk mengompresi representasi istilah dengan variabel bebas
data Term f x = Var x | Con (f (Term f x)) -- the Free monad, yet again
dalam sintaks yang dihasilkan secara bebas dari a Differentiable
dan Traversable
functor f
. Kami menggunakan Term f Void
untuk merepresentasikan kawasan tanpa variabel bebas, dan [D f (Term f Void)]
untuk merepresentasikan saluran tabung melalui kawasan tanpa variabel bebas baik ke variabel bebas yang terisolasi, atau ke persimpangan di jalur ke dua atau lebih variabel bebas. Harus menyelesaikan artikel itu kapan-kapan.
Untuk tipe tanpa nilai (atau setidaknya, tidak ada yang layak dibicarakan dengan teman yang sopan), Void
sangat berguna. Dan absurd
bagaimana Anda menggunakannya.
absurd
fungsi tersebut telah digunakan dalam artikel ini yang berhubungan denganCont
monad: haskellforall.com/2012/12/the-continuation-monad.html