Haskell 如何写一个“";从「;及;至;“的函数”;添加Void a==a";?
从文件:,它说: Bool和Add()是等价的,因为我们可以定义“from”和“to”函数:Haskell 如何写一个“";从「;及;至;“的函数”;添加Void a==a";?,haskell,algebraic-data-types,Haskell,Algebraic Data Types,从文件:,它说: Bool和Add()是等价的,因为我们可以定义“from”和“to”函数: to :: Bool -> Add () () to False = AddL () to True = AddR () from :: Add () () -> Bool from (AddL _) = False from (AddR _) = True 即: from (to a) == a to (from a) == a 然后他又给出了两个: Add Void a ===
to :: Bool -> Add () ()
to False = AddL ()
to True = AddR ()
from :: Add () () -> Bool
from (AddL _) = False
from (AddR _) = True
即:
from (to a) == a
to (from a) == a
然后他又给出了两个:
Add Void a === a
Add a b === Add b a
如何为这两个函数编写“from”和“to”函数
添加b===添加b a
您需要交换AddL/AddR
构造函数,如下所示:
to :: Add a b -> Add b a
to (AddL x) = AddR x
to (AddR x) = AddL x
-- from = to
为了
添加Void a==a
您需要一个多态函数void:void->a
to :: Add Void a -> a
to (AddL impossible) = void impossible
to (AddR x) = x
from :: a -> Add Void a
from x = AddR x
变量impossable
表示类型为Void
的“不存在”值。实际上没有这样的值(除了底部/未定义)。这就是为什么要排队
to (AddL impossible) = ...
实际上是不可访问的代码——它永远不会被执行
函数void
利用了一个事实,即它需要一个不可能的参数来凭空生成一个值a
。不幸的是,在Haskell中,void
无法定义,除非利用不确定性,例如
void :: Void -> a
void _ = error "This will never be reached"
一个更优雅、更正确的解决方案是
void :: Void -> a
void x = case x of
-- no constructors for Void, hence no branches here to do!
-- since all these (zero) branches have type `a`, the whole
-- case has type `a` (!!!)
但是,遗憾的是,Haskell禁止空的
case
构造。(在GHC 7.8中,如前所述,通过扩展允许使用空箱)
相比之下,在Coq或agda等依赖类型的语言中,上面的代码(稍加修改)就可以了。下面是Coq中的:
Inductive Void : Set := . (* No constructors for Void *)
Definition void (A : Set) (x : Void) : A :=
match x with
end .
在阿格达
data Void : Set where
-- no constructors
void : (A : Set) -> Void -> A
void A ()
-- () is an "impossible" pattern in Agda, telling the compiler that this argument
-- has no values in its type, so one can omit the definition entirely.
该库具有类型为Void->a
的函数。它抓住了“从错误开始,一切都遵循”的逻辑原则
它可用于从总和类型中删除Void
分支。直观地说,如果您的类型是a
或不可能的类型,那么它与a
几乎相同
import Data.Void
foo :: Either Void a -> a
foo x = either absurd id x
“但是,遗憾的是,Haskell禁止空的
大小写
构造。”不再是了,在7.8中,我们现在有了,它给出了一个特别针对Void
的示例。我试图调用到(AddL 1)
,但它报告:没有由literal 1产生的(Num a0)实例,类型变量
a0'是不明确的”。如何给它一个正确的参数?@Freewind使用to(AddL(1::Int))
来指定1
的类型。Haskell抱怨是因为1
周围的上下文不允许理解1
是否应该是Int
、Double
或任何其他数字类型。