gpt4 book ai didi

types - 在 F# 中表达存在类型

转载 作者:行者123 更新时间:2023-12-04 01:59:50 24 4
gpt4 key购买 nike

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

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

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

其中 real 是有意义的,例如:
type real = int * int

let addReal : real -> real -> real = undefined

现在,我需要一个函数 addPacked : PackedType -> 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)

在这里,我最终得到 NumberOp 存在。所以我在问是否有另一种方式来表达这一点。我无法更改 Packed[un]pack* 函数和 addPacked 的类型。

我找到了 this 答案。它指出有一个“众所周知的模式”,但文本难以阅读,我无法使其工作。

最佳答案

一般来说,您可以对类型进行编码

∃t.F<t>

作为
∀x.(∀t.F<t> → x) → 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) }

不幸的是,这里有很多样板。此外,我使用了无用的名称 Apply 作为每个辅助类型的抽象成员 - 如果您能找到您喜欢的名称,请随意替换更有意义的名称。我试图保持非常接近你的风格,但在我自己的代码中,我可能会避免在 addPacked 内解构记录,而是直接使用字段访问器。

关于types - 在 F# 中表达存在类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16284680/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com