Types 用F表示存在类型#

Types 用F表示存在类型#,types,f#,Types,F#,据我所知,F#不支持存在类型。所以,我在寻找另一种方式来表达我的想法 我有一个数据结构,它的内容可以用多种不同的方式解释。在这个特定的示例中,我假设可以将其视为int或real: type Packed = (* something sensible *) unit type PackedType = | PackedInt | PackedReal let undefined<'a> : 'a = failwith "undefined"

据我所知,F#不支持存在类型。所以,我在寻找另一种方式来表达我的想法

我有一个数据结构,它的内容可以用多种不同的方式解释。在这个特定的示例中,我假设可以将其视为int或real:

type Packed = (* something sensible *) unit

type PackedType = | PackedInt
                  | PackedReal


let undefined<'a> : 'a = failwith "undefined"

let unpackInt : Packed -> int = undefined
let unpackReal : Packed -> real = undefined

let packInt : int -> Packed = undefined
let packReal : real -> Packed = undefined
现在,我需要一个函数
addPacked:PackedType->Packed->Packed->Packed->Packed
。我希望它是一般性的,即:

type NumberOp = [forall t] { opPack : 't -> Packed; opUnpack : Packed -> 't; opAdd : 't -> 't -> 't }

let getNumberOp (t : PackedType) =
    match t with
    | PackedInt -> { opPack = packInt; opUnpack = unpackInt; opAdd = (+) }
    | PackedReal -> { opPack = packReal; opUnpack = unpackReal; opAdd = addReal }


let addPacked (t : PackedType) (a : Packed) (b : Packed) =
    let { opPack = pack; opUnpack = unpack; opAdd = add } = getNumberOp t
    pack <| add (unpack a) (unpack b)
type numberrop=[forall t]{opPack:'t->Packed;opUnpack:Packed->'t;opAdd:'t->'t->'t}
let getnumberrop(t:PackedType)=
匹配
|PackedInt->{opPack=packInt;opUnpack=unpacint;opAdd=(+)}
|PackedReal->{opPack=packReal;opUnpack=unpacreal;opAdd=addReal}
let addPacked(t:PackedType)(a:Packed)(b:Packed)=
让{opPack=pack;opUnpack=unpack;opAdd=add}=getnumberopt

pack通常,您可以对类型进行编码

∃t.F<t>
∃t、 F
作为

∀十,(∀t、 F→ 十)→ x
不幸的是,每个通用量化都需要在F#中创建一个新类型,因此除了F之外,忠实的编码还需要两种类型。下面是我们如何为您的示例执行此操作:

type 't NumberOps = {
    opPack : 't -> Packed
    opUnpack : Packed -> 't
    opAdd : 't -> 't -> 't 
}

type ApplyNumberOps<'x> = 
    abstract Apply :  't NumberOps -> 'x

// ∃ 't. 't NumberOps
type ExNumberOps =
    abstract Apply : ApplyNumberOps<'x> -> 'x

// take any 't NumberOps to an ExNumberOps
// in some sense this is the only "proper" way to create an instance of ExNumberOps
let wrap n = { new ExNumberOps with member __.Apply(f) = f.Apply(n) }

let getNumberOps (t : PackedType) =
    match t with
    | PackedInt -> wrap { opPack = packInt; opUnpack = unpackInt; opAdd = (+) }
    | PackedReal -> wrap { opPack = packReal; opUnpack = unpackReal; opAdd = addReal }

let addPacked (t : PackedType) (a : Packed) (b : Packed) =
    (getNumberOps t).Apply 
        { new ApplyNumberOps<_> with 
            member __.Apply({ opPack = pack; opUnpack = unpack; opAdd = add }) = 
                pack <| add (unpack a) (unpack b) }
type't numberrops={
opPack:'t->打包
opUnpack:打包->t
opAdd:'t->'t->'t
}
键入ApplyNumberOps'x
// ∃ 't、 "t数
ExNumberOps类型=

摘要应用:ApplyNumberOpsSee也谢谢。但我花了几个小时试图理解这一点,但仍然不太明白代码是如何工作的。更糟糕的是,我希望查看推断的类型会让事情变得更清楚,但代码无法编译。编译器说您的
新ApplyNumberOps
中的
Apply
有一个错误的类型,因此不会重写抽象方法。@kirelagin-如果您使用
unit
以外的任何东西作为
Packed
的定义,它将进行编译-
unit
由于.NET互操作的缘故有点特殊,并且不总是起作用与泛型很好地结合在一起。只需添加我的一小粒沙子;在过去的一周里,我一直在寻找类似的东西。这是一篇关于这一点的伟大文章,它涉及到导致存在类型实现的每个组件。
∀x.(∀t.F<t> → x) → x
type 't NumberOps = {
    opPack : 't -> Packed
    opUnpack : Packed -> 't
    opAdd : 't -> 't -> 't 
}

type ApplyNumberOps<'x> = 
    abstract Apply :  't NumberOps -> 'x

// ∃ 't. 't NumberOps
type ExNumberOps =
    abstract Apply : ApplyNumberOps<'x> -> 'x

// take any 't NumberOps to an ExNumberOps
// in some sense this is the only "proper" way to create an instance of ExNumberOps
let wrap n = { new ExNumberOps with member __.Apply(f) = f.Apply(n) }

let getNumberOps (t : PackedType) =
    match t with
    | PackedInt -> wrap { opPack = packInt; opUnpack = unpackInt; opAdd = (+) }
    | PackedReal -> wrap { opPack = packReal; opUnpack = unpackReal; opAdd = addReal }

let addPacked (t : PackedType) (a : Packed) (b : Packed) =
    (getNumberOps t).Apply 
        { new ApplyNumberOps<_> with 
            member __.Apply({ opPack = pack; opUnpack = unpack; opAdd = add }) = 
                pack <| add (unpack a) (unpack b) }