Haskell 是否存在需要使用bottom才能获得正确类型的数据结构?

Haskell 是否存在需要使用bottom才能获得正确类型的数据结构?,haskell,types,Haskell,Types,Haskell中是否存在绝对需要使用底部值的类型,即未定义的?或者它只是用来在代码运行过程中编译代码 我认为可能存在一种罕见的类型,它需要undefined来完成它的构造,list只需要1:[]就可以了,但可能数据类型太复杂了,需要undefined`来完成它的构造 是否有更复杂的构造函数需要键入未定义的?有时,您只想传递一个值来传递该值的类型,而不关心实际值。例如asTypeOf::a->a->a。它不检查is seconds参数,它只是在那里设置类型a: Prelude> maxBou

Haskell中是否存在绝对需要使用底部值的类型,即未定义的
?或者它只是用来在代码运行过程中编译代码

我认为可能存在一种罕见的类型,它需要
undefined
来完成它的构造,list只需要
1:[]
就可以了,但可能数据类型太复杂了,需要undefined`来完成它的构造


是否有更复杂的构造函数需要键入
未定义的

有时,您只想传递一个值来传递该值的类型,而不关心实际值。例如
asTypeOf::a->a->a
。它不检查is seconds参数,它只是在那里设置类型
a

Prelude> maxBound `asTypeOf` (0::Word)
18446744073709551615
Prelude> maxBound `asTypeOf` (0::Int)
9223372036854775807
Prelude> maxBound `asTypeOf` (undefined::Int)
9223372036854775807
如您所见,
asTypeOf
在将
undefined
作为其第二个参数的值传递时非常有效,因为任何
Int
类型化的值都会导致
maxBound
被视为
Int
maxBound

您可能会争辩说,将值传递给从不使用的
asTypeOf
是一个愚蠢的想法。那种类型感觉不对。相反,您只需要传递一些包含类型信息的内容。虽然
代理
的标准版本略有不同,但仍有使用该思想的
代理
类型的实现。一个简单的
代理
实现可以如下工作:

-- Note: No data constructor at all.
-- This type is uninhabitated, the only possible value is undefined
data Proxy a

-- generator function for a proxy value. As there is no value, it has to return
-- undefined.
proxy :: Proxy a
proxy = undefined

asProxiedBy :: a -> Proxy a -> a
asProxiedBy x _ = x
使用此代码,您可以编写

*Main> maxBound `asProxiedBy` (proxy :: Proxy Int)
9223372036854775807

在这个修订的示例中,将
asTypeOf
替换为
asProxiedBy
,您不再传递未使用的值,而是将未定义的值作为引用类型传递。为了避免拼写丑陋的单词
undefined
,引入了
proxy
方法来生成所有
proxy
类型的
undefined
值。

最后我找到了一些适合undefined的示例:

newtype Wrap = W {w :: Wrap} deriving Show

www = W $ W $ W $ undefined
你可以数一数(没有尽头):

在这里,
Wrap
需要
undefined
结束

class Peano a where
    zero :: a
    next :: a -> a


alt_zero, alt_one, alt_two, alt_three :: (Peano a) => a
alt_zero = undefined
alt_one = next alt_zero -- = succ undefined
alt_two = next alt_one -- = succ (succ undefined)
alt_three = next alt_two -- = succ (succ (succ undefined))
在这里,您可以创建1、2、3而无需实例,也可以给出具体类型

data Nat = Z | S Nat deriving Show

instance (Peano Nat) where
  zero = Z
  next = S

instance (Peano Wrap) where
  zero = undefined
  next = W

countN :: Nat -> Int 
countN Z = 0
countN (S n) = (countN n) + 1

以及一些实现。我知道如果我再多搜索一点,我会找到一些东西

我还不确定我是否理解这个问题。你的问题是,是否有任何一种类型的任何一个具有该类型的术语是底部的?或者你是在问,是否有哪种类型的惯用用法涉及某个地方的底部?还是别的什么…?@DanielWagner非常感谢!有了你们的问题,我可以找到一些非常好的信息。看起来像一个例子。:)空树将为
空=节点0未定义未定义
。(当然,你可以把任何东西放在那里,包括
empty
节点10000000 empty
;这不是一个好的设计。)是的,但你真的不应该使用那种代理,因为它让你使用
未定义的
!代理的通常定义是
数据代理a=Proxy
。模式的全部要点是使用
代理
——一个完全定义的值,而不是
未定义的
,这样就可以完全避免需要
未定义的
。在现代Haskell中,我相信几乎不需要
asTypeOf
,如果有的话。由于
ScopedTypeVariables
,编写
x::T
现在总是可能的,而且它比
x`asTypeOf`y
更好地记录了预期的类型,在这里您需要
y
成为预期的类型。我们从不需要使用“`x
asTypeOf
(undefined::T)”,因为这相当于
x::T
,当我们不能显式地编写
T
时,我们需要
asTypeOf
,但我们手头有一个该类型的值,IIRC。或
数据Void=Void!Void
,或者如果您不关心Haskell 98,
数据Void
。但这些都很无聊。有更多有趣的使用底部在那里。看看我为
Data.Sequence.zipWith
@dfeuer编写的定义,确实有!l=Seq$Deep 3(一个(元素(1,2)))EmptyT(两个未定义的元素(元素(5,6))
Wrap
不需要
undefined
结束:
x=W x
不是底部(内部任何地方都不包含底部)。也许你想让它变成一个
newtype
?@Daniel Wagner的确,你总是对的:)。这与“n=n+1”不一样吗?是的,
W
是一个函数。但数据构造函数是特殊的:它们标记允许停止对WHNF的评估的位置。仅非构造函数应用程序不共享此属性。另见“保护递归”
x=W x
受保护,而
x=1+x
不受保护。
data Nat = Z | S Nat deriving Show

instance (Peano Nat) where
  zero = Z
  next = S

instance (Peano Wrap) where
  zero = undefined
  next = W

countN :: Nat -> Int 
countN Z = 0
countN (S n) = (countN n) + 1