F#报价,阵列和在构造函数中自我标识
问题描述:
我认为这是F#的一个众所周知的限制,但我找不到什么好的解决办法?F#报价,阵列和在构造函数中自我标识
所以,这里是代码(我试图使它作为简单越好,所以可能看起来它没有任何意义):
[<ReflectedDefinition>]
type Human (makeAName: unit -> string) as self =
let mutable cats : Cat array = [| |]
do
// get a cat
cats <- Array.append cats [| new Cat (self, makeAName()) |]
member this.Cats = cats
and
[<ReflectedDefinition>]
Cat (owner : Human, name : string) = class end
编译器说:
错误FS0452:报价不包含内联汇编代码或图案阵列
匹配
其实它是as self
和数组属性获取器的组合,它打破了一切。
的这里的要点是:
- 我真的想用数组,因为我想WebSharper到我的收藏转化为JavaSript阵列。
- 我真的需要构造函数中的自我标识符。
- 我真的需要类(即功能风格不起作用)。
- 按方法自标识符(
member this.Foo
)正常工作。
我能想到的一种解决方法是将构造函数设置为private并使用静态方法构造对象。这样我不需要as self
。但它是愚蠢的。
有没有更好的选择?
更新:
这里是一个更简单的例子:
[<ReflectedDefinition>]
type User (uid: int) as self =
let ROOT_UID = 0
member this.isRoot = (uid = ROOT_UID)
随着as self
我甚至不能定义一个类常量。那么,这实际上是一个单独的问题,但我会在这里问:如何在这种特殊情况下定义类常量?
答
我不认为它是愚蠢的。为了清晰起见,我们实际上更喜欢静态构造函数方法,即使在不使用WebSharper的代码中也是如此。在整个IntelliFactory代码库中,我们很少使用self
。
您遇到了两个令人讨厌的F#编译器和引用限制。正如你所指出的,静态方法可以解决问题self
:
[<ReflectedDefinition>]
type Human private (cats: ref<Cat []>) =
member this.Cats = !cats
static member Create(makeAName: unit -> string) =
let cats = ref [| |]
let h = Human(cats)
let cat = Cat(h, makeAName())
cats := [| cat |]
h
and [<ReflectedDefinition>] Cat (owner: Human, name: string) =
class
end
还有许多其他的方式来实现这一点,例如,你可以摆脱ref
间接的。
其次,您经常会在ReflectedDefinition
代码中获得的数组操作,即使是普通的静态方法。这通常可以通过使用库函数而不是直接数组访问来解决(Array.iter
,Array.map
)。
对于第二个例子,你真的想这样:
[<ReflectedDefinition>]
module Users =
[<Literal>]
let ROOT_UID = 0
type User(uid: int) =
member this.isRoot = (uid = ROOT_UID)
的[<Literal>]
注释将让你对你的常量,它可以方便的,如果有一个以上的模式匹配。
对于您的观点:
- 我真的想用阵列 - 这应该是OK
- 我真的需要一个自我标识符 - 这是从来没有必要,就像构造不
- 我真正需要的类(即实用的风格将无法正常工作) - 绝对不是真正的
- 每方法自标识符(成员this.Foo)做工精细 - 是的,是有用的
静态构造函数 - 很好。谈到第二个例子,好的,正确的,模块常量可以工作,但我实际上是一个类常量,这就是为什么我想放在类中。让类内的类常量(而不是污染模块名称空间)看起来是一个合理的事情。 – kirelagin 2013-03-29 05:16:36