Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 什么';这是数据中荒谬的函数。Void对我们有用吗?_Haskell_Type Theory_Curry Howard - Fatal编程技术网

Haskell 什么';这是数据中荒谬的函数。Void对我们有用吗?

Haskell 什么';这是数据中荒谬的函数。Void对我们有用吗?,haskell,type-theory,curry-howard,Haskell,Type Theory,Curry Howard,Data.Void中的函数具有以下签名,其中Void是该包导出的逻辑上未占用的类型: -- | Since 'Void' values logically don't exist, this witnesses the logical -- reasoning tool of \"ex falso quodlibet\". absurd :: Void -> a 我确实知道足够的逻辑,可以得到文档中的注释,即通过类型对应的命题,这对应于有效的公式⊥ → a 我感到困惑和好奇的是:在什么样

Data.Void
中的函数具有以下签名,其中
Void
是该包导出的逻辑上未占用的类型:

-- | Since 'Void' values logically don't exist, this witnesses the logical
-- reasoning tool of \"ex falso quodlibet\".
absurd :: Void -> a
我确实知道足够的逻辑,可以得到文档中的注释,即通过类型对应的命题,这对应于有效的公式
⊥ → a

我感到困惑和好奇的是:在什么样的实际编程问题中,这个函数有用?我在想,在某些情况下,它作为一种类型安全的方式来彻底处理“不可能发生”的案例可能是有用的,但我对Curry Howard的实际用途了解不够,无法判断这个想法是否在正确的轨道上

编辑:最好是Haskell中的示例,但如果有人想使用依赖类型的语言,我不会抱怨

我在想,在某些情况下,作为一种类型安全的方式,它可能是非常有用的,可以彻底地处理“不可能发生”的情况

这是完全正确的

你可以说,
荒谬
并不比
常量(错误“不可能”)
更有用。但是,它是类型受限的,因此它的唯一输入可以是
Void
类型的内容,这是一种故意不被占用的数据类型。这意味着没有可以传递给
的实际值。如果你最终进入了一个代码分支,类型检查器认为你有权访问类型为
Void
的东西,那么,好吧,你处于一个荒谬的境地。因此,您只需使用
荒谬
,基本上就可以标记此代码分支永远不会被访问

“Ex falso quodlibet”字面意思是“从[a]错误的[proposition],任何事情都会随之而来”。因此,当您发现您持有的数据类型为
Void
,您就知道手中有虚假证据。因此,你可以填补任何你想要的漏洞(通过
荒谬的
),因为从一个错误的命题,任何事情都会随之而来

我写了一篇关于导管背后的想法的博客,其中有一个使用
荒谬的
的例子


通常,您可以使用它来避免明显的部分模式匹配。例如,从以下位置获取数据类型声明的近似值:

然后你可以像这样使用
荒谬的
,例如:

handleLOARules :: (String -> a) -> LinesOfActionsRuleSet -> a
handleLOARules f r = case r of
    Known   a -> absurd a
    Unknown s -> f s

生活有点艰难,因为哈斯克尔并不严格。一般用例是处理不可能的路径。比如说

simple :: Either Void a -> a
simple (Left x) = absurd x
simple (Right y) = y
这在某种程度上是有用的。考虑一个简单的类型:<代码>管道< /代码>

data Pipe a b r
  = Pure r
  | Await (a -> Pipe a b r)
  | Yield !b (Pipe a b r)
这是Gabriel Gonzales的
pipes
库中标准管道类型的严格简化版本。现在,我们可以将从不产生(即消费者)的管道编码为

这真的永远不会让步。这意味着
消费者的正确折叠规则是

foldConsumer :: (r -> s) -> ((a -> s) -> s) -> Consumer a r -> s
foldConsumer onPure onAwait p 
 = case p of
     Pure x -> onPure x
     Await f -> onAwait $ \x -> foldConsumer onPure onAwait (f x)
     Yield x _ -> absurd x
或者,在与消费者打交道时,您可以忽略收益率案例。这是此设计模式的通用版本:使用多态数据类型和
Void
,在需要时消除各种可能性

Void
最经典的用法可能是在CPS中

type Continuation a = a -> Void
也就是说,
延续
是一个永远不会返回的函数
Continuation
是“not”的类型版本。从中我们得到了CPS的单子(对应于经典逻辑)


因为Haskell是纯的,所以我们不能从这种类型中得到任何东西。

考虑由自由变量参数化的lambda项的这种表示。(见Bellegarde和Hook 1994、Bird和Paterson 1999、Altenkirch和Reus 1999的论文。)

您当然可以将其设置为
函子
,捕获重命名的概念,以及
单子
捕获替换的概念

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))

现在考虑封闭的术语:这些是<代码> TM虚空< /代码>的居民。您应该能够将封闭项嵌入具有任意自由变量的项中。怎么做

fmap absurd :: Tm Void -> Tm a
当然,问题是这个函数将遍历这个术语,完全不做任何事情。但这比不完美的感觉更诚实。这就是为什么
vacuous
被添加到
Data.Void

或者写一个评估员。以下是
b
中带有自由变量的值

data Val b
  =  b :$$ [Val b]                              -- a stuck application
  |  forall a. LV (a -> Val b) (Tm (Maybe a))   -- we have an incomplete environment
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
我刚刚将lambdas表示为闭包。通过将
a
中的自由变量映射到
b
上的值来参数化计算器

data Val b
  =  b :$$ [Val b]                              -- a stuck application
  |  forall a. LV (a -> Val b) (Tm (Maybe a))   -- we have an incomplete environment
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
你猜对了。在任何目标上评估闭合项

eval absurd :: Tm Void -> Val b
更一般地说,
Void
很少单独使用,但是当您想要以某种表示不可能的方式实例化类型参数时(例如,在这里,在封闭项中使用自由变量),它非常方便。通常,这些参数化类型带有高阶函数,将对参数的操作提升为对整个类型的操作(例如,此处,
fmap
>=
eval
)。因此,您将
作为
Void
上的通用操作传递

再举一个例子,想象一下使用
或EV
捕获计算,这些计算可能会给您一个
v
,但可能会引发
e
类型的异常。您可以使用此方法统一记录不良行为的风险。对于此设置中表现良好的计算,将
e
设置为
Void
,然后使用

either absurd id :: Either Void v -> v
安全地或

either absurd Right :: Either Void v -> Either e v
在不安全的世界中嵌入安全组件

哦,最后一声欢呼,处理一个“不可能发生”的问题。它显示在通用拉链结构中,光标无法到达的任何地方

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!
我决定不删除其余的,尽管它并不完全相关

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)
事实上,也许这是相关的。如果您有冒险精神,这将展示如何使用
Void
压缩带有自由变量的术语表示

data Term f x = Var x | Con (f (Term f x))   -- the Free monad, yet again
在由
可微
T自由生成的任何语法中
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)
data Term f x = Var x | Con (f (Term f x))   -- the Free monad, yet again
type Void' = forall a . a
type Sink i m r = Pipe i i Void () m r
type Continuation r a = a -> Cont r Void
shrink : (xs : Vect (S n) a) -> Elem x xs -> Vect n a
shrink (x :: ys) Here = ys
shrink (y :: []) (There p) = absurd p
shrink (y :: (x :: xs)) (There p) = y :: shrink (x :: xs) p