可空嵌套对象和 Maybe Monad

发布于 2024-12-05 05:03:40 字数 1666 浏览 1 评论 0原文

我正在努力实现一个可能的 monad - 在这个例子中我将其称为 Nullable 。

Nullable 类的实现如下:

Public NotInheritable Class Nullable(Of TClass)

    Private _value As TClass
    Private _hasValue As Boolean

    Public Shared Function Create(ByVal value As TClass) As Nullable(Of TClass)
        Return New Nullable(Of TClass)(value)
    End Function
    Public Shared Function Create() As Nullable(Of TClass)
        Return New Nullable(Of TClass)()
    End Function

    Private Sub New()
        HasValue = False
    End Sub
    Private Sub New(theValue As TClass)
        Value = theValue
        HasValue = True
    End Sub

    Public Property Value() As TClass
        Get
            Return _value
        End Get
        Private Set(value As TClass)
            _value = value
        End Set
    End Property

    Public Property HasValue() As Boolean
        Get
            Return _hasValue
        End Get
        Private Set(value As Boolean)
            _hasValue = value
        End Set
    End Property

End Class

有一个父类实现为

Class Parent
    Public Property ChildClass as Nullable(Of Child)
End Class

,而子类只是

Class Child
    Public Property ID as String
    ... other properties below ...
End Class

monad 的实现方式,目前我需要发出以下命令来访问嵌套子类上的属性

dim id = MyParentClass.ChildClass.Value.ID

,但理想情况下我是这样的想要做的是拥有以下语句

dim id = MyParentClass.ChildClass.Id

,如果 ChildClass 为 null,则仅返回属性类型的默认值。

我尝试使用默认属性来实现此功能,并通过属性将值设置为默认值,但它无法编译。

这是否可能,或者也许有更好的构建它的方法 - 或者也许我只是还没有“得到”可能的单子?

许多 TIA

Simon

I'm struggling to implement a maybe monad - which I've called Nullable in this example.

The Nullable Class is implemented as follows:

Public NotInheritable Class Nullable(Of TClass)

    Private _value As TClass
    Private _hasValue As Boolean

    Public Shared Function Create(ByVal value As TClass) As Nullable(Of TClass)
        Return New Nullable(Of TClass)(value)
    End Function
    Public Shared Function Create() As Nullable(Of TClass)
        Return New Nullable(Of TClass)()
    End Function

    Private Sub New()
        HasValue = False
    End Sub
    Private Sub New(theValue As TClass)
        Value = theValue
        HasValue = True
    End Sub

    Public Property Value() As TClass
        Get
            Return _value
        End Get
        Private Set(value As TClass)
            _value = value
        End Set
    End Property

    Public Property HasValue() As Boolean
        Get
            Return _hasValue
        End Get
        Private Set(value As Boolean)
            _hasValue = value
        End Set
    End Property

End Class

There is a parent Class implemented as

Class Parent
    Public Property ChildClass as Nullable(Of Child)
End Class

and a Child Class is simply

Class Child
    Public Property ID as String
    ... other properties below ...
End Class

The way the monad is implemented at the moment I would need to issue the following to access a property on the nested child class

dim id = MyParentClass.ChildClass.Value.ID

but ideally what I'd like to be able to do is to have the following statement

dim id = MyParentClass.ChildClass.Id

and if the ChildClass is null then just return a default value for the property type.

I tried implementing this using Default Properties and setting the Value as default via an attribute but it wouldn't compile.

Is that going to be possible or perhaps there is a better way of architecting it - or maybe I just haven't 'got' the maybe monad?

Many TIAs

Simon

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

画▽骨i 2024-12-12 05:03:40

好吧,Maybe 本身的定义只是一个可能存在也可能不存在的单个值,所以这么多就可以了。顺便说一句,如果您出于某种原因不喜欢“Maybe”这个名称,我建议考虑使用“Option”而不是“Nullable”,因为 Nullable 已被 .NET 使用(对于相同的情况)目的,甚至 - 但仅限于值类型),而 Option 是 F# 所称的,并且一致性很好。

不管怎样,基本上你可以用这样的值做两件事——对值应用转换(如果有的话),并折叠嵌套层(例如,将可空的“foo”变成可空的“foo”) “foo”)。考虑到这些以及构建新价值观的能力,你可以做其他一切事情。

“转换”操作最直接的实现方式是采用 lambda(比较 LINQ 使用的 Select 方法 - 这是同一件事),然后将其应用于包装的值,或者如果存在则将其丢弃没有价值。 “折叠”操作非常简单;如果存在的话,只保留内在价值。 LINQ 在这里是一种非常自然的方法——您可以将Maybe 视为表示最多一个元素的可枚举序列。

也就是说,您可能不希望到处使用 lambda 或 LINQ 表达式。坏消息是我认为没有其他办法。

我怀疑您在这里真正想要的是使用常规方法调用语法隐式应用“转换”操作,同时如果该方法还返回可为空的内容,并且可能提供默认值,则自动应用“折叠”操作尝试直接使用缺失值时的值。这是一个合理的设计,并且使用起来非常方便,但我认为在这里不可能(我自己使用 C# 尝试了几个变体,并且我认为 VB.NET 的差异不足以提供帮助)。像这样的方案的最终结果是能够对空值调用方法,并返回空值而不是空引用异常。作为一个例子,这里有 Ruby 中类似的东西,用一些元编程技巧实现,我认为 VB 没有.NET可以支持。我依稀记得在 Javascript 和其他一些语言中看到过类似的想法。

简而言之,我认为您的想法基本上是正确的,但遗憾的是您想要完成的事情是不可能的。

Well, the definition of Maybe itself is simply a single value that may or may not be present, so that much is fine. Incidentally, if you don't like the name "Maybe" for some reason, I'd suggest considering "Option" instead of "Nullable", since Nullable is already used by .NET (for the same purpose, even--but only with value types), while Option is what F# calls it and consistency is nice.

Anyway, there are essentially two things you can do with such a value--apply a transformation to the value (if there is one), and collapse nested layers (e.g., turning a nullable of a nullable of "foo" into just a nullable of "foo"). You can do everything else given those and the ability to construct new values.

The "transform" operation is most straightforwardly implemented by taking a lambda (compare the Select method used by LINQ--it's the same thing), and either applying it to the wrapped value or discarding it if there is no value. The "collapse" operation is pretty simple; just keep the inner value if it exists. LINQ is a very natural approach here--you can think of Maybe as representing an enumerable sequence of at most one element.

That said, you probably don't want to be using lambdas or LINQ expressions everywhere. The bad news is that I don't think there's any other way.

What I suspect you really want here is to apply the "transform" operation implicitly using regular method call syntax, while automatically applying the "collapse" operation if the method also returns something nullable, and possibly providing a default value when attempting to use a missing value directly. This is a reasonable design, and very handy to use, but I don't think it's possible here (I've tried a couple variations myself using C#, and I don't think VB.NET differs enough to help). The end result of a scheme like this is the ability to call methods on null values, and get a null value back instead of a null reference exception. As an illustration, here's something similar in Ruby, implemented with a bit of metaprogramming trickery that I don't think VB.NET can support. I vaguely recall seeing similar ideas done in Javascript and some other languages.

In short, I think you have basically the right idea but what you're trying to accomplish sadly isn't possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文