从构造函数中通用提取
在 F# 和 OCaml 中,我最终编写了很多代码,例如
type C = Blah of Whatever
let d = Blah (createWhatever ()) // so d is type C
...
let x = match d with | Blah b -> b
“我想要的是这样的”
...
let x = peel d
,其中剥离适用于任何构造函数/判别器。
当然我不是唯一对此感到恼火的人。
编辑: 很好的答案,但我没有代表对它们进行投票。 这种情况怎么样?
member self.Length = match self with | L lab -> lab.Length
In F# and OCaml I wind up writing a lot of code like
type C = Blah of Whatever
let d = Blah (createWhatever ()) // so d is type C
...
let x = match d with | Blah b -> b
What I'd like is this
...
let x = peel d
Where peel would work for any constructor/discriminator.
Surely I'm not the only one annoyed by this.
edit:
Good answers, but I don't have the rep to vote on them.
How about this situation?
member self.Length = match self with | L lab -> lab.Length
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(4)
伴我老2024-11-08 10:44:28
适用于 DU...需要调整才能与类构造函数一起使用:
open Microsoft.FSharp.Reflection
let peel d =
if obj.ReferenceEquals(d, null) then nullArg "d"
let ty = d.GetType()
if FSharpType.IsUnion(ty) then
match FSharpValue.GetUnionFields(d, ty) with
| _, [| value |] -> unbox value
| _ -> failwith "more than one field"
else failwith "not a union type"
顺便说一句:我通常不会做这样的事情,但既然你问了...
~没有更多了~
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
不可能安全地做到这一点:如果
peel
是一个函数,它的类型是什么?它无法输入,因此不能成为该语言中的“好人”。您可以:
使用反射(在 F# 中)或类型破坏函数(在 OCaml 中是
Obj
模块),但是您会得到不精确类型的不安全内容,因此它相当难看并且“使用时请自行承担风险”使用元编程为每种类型生成不同版本的
peel
。例如,使用 type-conv OCaml 工具,您可能有 < code>type blah = Blah of Something 隐式定义函数peel_blah
,并且type foo = Foo of Something
定义peel_foo
。< /p>恕我直言,更好的解决方案是......首先不需要这样的剥离。我看到两种可能性:
您可以使用巧妙的模式而不是函数:通过使用
let (Blahwhat) = f x
或fun (Blahwhat) -> ...
,您不再需要解包函数。或者你可以不写
type blah = Blah of what
,而是写输入 blah = (blah_tag * 随便) 和 blah_tag = Blah
这样,您就没有总和类型,而是产品类型(您编写
(Blah,whatever)
),并且您的peel
只是snd
。对于每个blah
、foo
等,您仍然有不同的(不兼容)类型,但有一个统一的访问接口。It is not possible to do that safely : if
peel
was a function, what would be its type ? It cannot be typed and therefore cannot be a "good guy" in the language.You may :
use reflection (in F#) or type-breaking functions (in OCaml it's the
Obj
module), but you will get something unsafe with an imprecise type, so it's rather ugly and "use at your own risk"use metaprogramming to generate different versions of
peel
at each type for you. For example, using the type-conv OCaml tool, you may havetype blah = Blah of something
define a functionpeel_blah
implicitly, andtype foo = Foo of something
definepeel_foo
.The better solution imho is... not to need such a
peel
in the first place. I see two possibilities:You may use clever patterns instead of a function : by using
let (Blah whatever) = f x
, orfun (Blah whatever) -> ...
, you don't need an unpacking function anymore.Or you may, instead of writing
type blah = Blah of what
, writetype blah = (blah_tag * whatever) and blah_tag = Blah
This way, you don't have a sum type but a product type (you write
(Blah, whatever)
), and yourpeel
is justsnd
. You still have a different (incompatible) type for eachblah
,foo
etc, but a uniform access interface.