Haskell 什么是;“存在”;哈斯克尔型系统中的平均值?

Haskell 什么是;“存在”;哈斯克尔型系统中的平均值?,haskell,exists,forall,quantifiers,Haskell,Exists,Forall,Quantifiers,我正在努力理解与Haskell类型系统相关的exists关键字。据我所知,Haskell中默认没有这样的关键字,但是: 在像下面这样的声明中,有一些添加了它们。MKACUM s(a->s->s)(s->a) 我看过一篇关于它们的论文,并且(如果我没记错的话)它说exists关键字对于类型系统是不必要的,因为它可以通过forall 但我甚至不能理解存在的意义 当我说,forall a。a->Int,它意味着(据我理解,我猜是不正确的)“对于每一个(类型)a,都有一个类型a->Int”的函数:

我正在努力理解与Haskell类型系统相关的
exists
关键字。据我所知,Haskell中默认没有这样的关键字,但是:

  • 在像下面这样的声明中,有一些添加了它们。MKACUM s(a->s->s)(s->a)
  • 我看过一篇关于它们的论文,并且(如果我没记错的话)它说
    exists
    关键字对于类型系统是不必要的,因为它可以通过
    forall
但我甚至不能理解
存在的意义

当我说,
forall a。a->Int
,它意味着(据我理解,我猜是不正确的)“对于每一个(类型)
a
,都有一个类型
a->Int
”的函数:

当我说
时,存在一个错误。a->Int
,它到底是什么意思?“至少有一种类型
a
,其函数类型为
a->Int
”?为什么要写这样的声明?目的何在?语义学?编译器行为

myF2 :: exists a . a -> Int
myF2 _ = 123
-- okay, there is at least one type `a` for which there is such function
-- because, in fact, we have just defined it for any type
-- and there is at least one type...
-- so these two lines are equivalent to the two lines above
请注意,这并不是一个真正的可以编译的代码,只是我想象的一个例子,然后我听说了这些量词


顺便说一句,我在Haskell并不完全是一个新手(可能像二年级学生),但我在这些方面缺乏数学基础。

它的确切意思是“存在一个类型
a
,我可以在构造函数中提供以下类型的值。”请注意,这与“在我的构造函数中,
a
的值是
Int
”;在后一种情况下,我知道类型是什么,我可以使用自己的函数,将
Int
s作为参数,对数据类型中的值执行其他操作

因此,从实用的角度来看,存在类型允许您在数据结构中隐藏底层类型,迫使程序员只使用您在其上定义的操作。它表示封装。

因此,以下类型不是很有用:

data Useless = exists s. Useless s
因为我对该值无能为力(不完全正确;我可以
seq
it);我对其类型一无所知。

实现exists关键字。下面是其文档中的一个示例

x2 :: exists a . (a, a -> Int)
x2 = (3 :: Int, id)

xapp :: (exists b . (b,b -> a)) -> a
xapp (v,f) = f v

x2app = xapp x2
还有一个:

mkx :: Bool -> exists a . (a, a -> Int)
mkx b = if b then x2 else ('a',ord)

y1 = mkx True -- y1 :: (C_3_225_0_0,C_3_225_0_0 -> Int)
y2 = mkx False -- y2 :: (C_3_245_0_0,C_3_245_0_0 -> Int)

mixy = let (v1,f1) = y1
            (v2,f2) = y2
       in f1 v2
“mixy导致类型错误。但是,我们可以很好地使用y1和y2:

ezyang也在博客上写得很好:

当我说,对于所有a.a->Int,它 意思是(据我所知 我想这是不对的 (类型)a,有a的功能 键入a->Int::

关闭,但不完全关闭。它意味着“对于每个类型a,此函数可以被视为具有类型a->Int”。因此,
a
可以专用于调用方选择的任何类型

在“exists”的情况下,我们有:“有一些(特定的,但未知的)类型a,因此这个函数的类型是a->Int”。因此
a
必须是一个特定的类型,但是调用者不知道是什么


注意,这意味着这个特定类型(
存在于a.a->Int
)并不是那么有趣——除了传递一个“bottom”之外,没有任何有用的方法来调用该函数“值,例如
未定义
让x=x在x中
。更有用的签名可能是
exists A。fooa=>Int->a
。它表示函数返回一个特定的类型
a
,但您不知道是什么类型。但是您知道它是
Foo
的一个实例,所以您可以使用它做一些有用的事情,尽管您不知道它的“真实”类型。

我遇到的存在类型的用法是与我的

我的调解代码有点像一个商人。它不关心玩家的类型,只关心所有玩家实现
Player
typeclass中给出的钩子

class Player p m where
  -- deal them in to a particular game
  dealIn :: TotalPlayers -> PlayerPosition -> [Card] -> StateT p m ()

  -- let them know what another player does
  notify :: Event -> StateT p m ()

  -- ask them to make a suggestion
  suggest :: StateT p m (Maybe Scenario)

  -- ask them to make an accusation
  accuse :: StateT p m (Maybe Scenario)

  -- ask them to reveal a card to invalidate a suggestion
  reveal :: (PlayerPosition, Scenario) -> StateT p m Card
现在,庄家可以保留一份类型为
Player pm=>[p]
的玩家列表,但这会限制玩家数量 所有的球员都是同一类型的

那太狭窄了。如果我想有不同类型的玩家,每一个都实现了呢 以不同的方式,让他们互相竞争

因此,我使用
existentitypes
为玩家创建包装:

-- wrapper for storing a player within a given monad
data WpPlayer m = forall p. Player p m => WpPlayer p
现在我可以很容易地保留一份不同类型的球员名单。经销商仍然可以轻松地与客户互动 使用
Player
typeclass指定的接口的播放器

考虑构造函数的类型
WpPlayer

    WpPlayer :: forall p. Player p m  => p -> WpPlayer m
除了前面的forall,这是非常标准的haskell。适用于所有类型 满足契约的p
Player p m
,构造函数
WpPlayer
映射类型为
p
到类型为
wpm
的值

有趣的一点是解构器:

    unWpPlayer (WpPlayer p) = p
unpplayer
的类型是什么?这行吗

    unWpPlayer :: forall p. Player p m => WpPlayer m -> p
不,不是真的。一系列不同类型的
p
可以满足
playerm
合同的要求 使用特定类型
m
。我们给了
WpPlayer
构造函数一个特殊的 类型p,因此它应该返回相同的类型。所以我们不能对所有的
使用

我们真正能说的是存在某种类型的p,它满足
Player-pm
契约 使用类型
m

    unWpPlayer :: exists p. Player p m => WpPlayer m -> p

我期待着一个很好的答案。谢谢您的提问。此链接:可能会有所帮助。
Ctrl-F存在
-只出现一次,而不是出现在正文中。。。但我正在读,非常感谢much@valya:是的。与此相关的哈斯凯尔博士论文或许也值得一读。对这个问题的回答可能会有所帮助:也许你可以用一个并非无用的例子来详细阐述一下?非常感谢你。(顺便说一句,你的博客很棒,教了我很多)这是实现OOP多态性的功能性方法。既然在Haskell中不存在exists,那么对你来说,所有符号的等效形式是什么
    unWpPlayer :: forall p. Player p m => WpPlayer m -> p
    unWpPlayer :: exists p. Player p m => WpPlayer m -> p