此处是F#的初学者
我想创建一个类型,它是具有至少一个元素的另一种具体类型(事件)的序列。以后可以随时添加任何其他元素。通常,在C#中,我将使用私有List
但是我想使用功能性方法而不是模仿C#方法。或至少尝试一下。
我的思路:
让我们创建一个“ seq”类型,并为它提供一个需要Event类型实例的构造函数
type Event = Event of string
type PublishedEvents = EventList of seq<Event> with
static member create (event:Event) = EventList(Seq.singleton event)
现在,我们添加一个“ add”方法来添加另一个可选的Event实例
type PublishedEvents with
member this.add(event:Event) = Seq.append this [event]
但这不起作用,F#抱怨“ this”与seq <'a>不兼容。
所以我尝试了这个:
type PublishedEvents with
member this.add (event:Event) : PublishedEvents = EventList(Seq.append this [event])
现在,它抱怨“此”与seq EventList of seq<Event>
...所以我想我需要以某种方式转换{{ 1}}返回EventList
,这样我就可以使用seq<Event>
吗?
Seq.append
但是我不知道该怎么做。
我什至朝着正确的方向前进吗?模仿带有支持字段的C#类是否更好?还是我错过了什么?
答案 0 :(得分:5)
事件的实际顺序包装在一个EventList
区分的联合案例中。
您可以打开包装,然后重新包装,如下所示:
type PublishedEvents with
member this.add(event:Event) =
match this with
| EventList events -> Seq.append events [event] |> EventList
但是,如果只是一个PublishedEvents
案例,其中包含一个序列,需要您反复包装和拆包值,那么我首先要质疑创建此EventList
类型的价值。 / p>
此外,请注意,此add
方法不会更改现有的PublishedEvents
。由于Seq.append
的工作方式,它创建了一个具有新事件序列的新事件,因为seq<'a>
实际上只是System.Collections.Generic.IEnumerable<'a>)
的F#名称。
此外,您的方法不会阻止创建非空事件序列。 EventList
是PublishedEvents
的公共构造函数,因此您可以编写:
EventList []
使类型系统强制执行非空序列的一种简单方法是:
type NonEmptySeq<'a> = { Head : 'a; Tail : seq<'a> } with
static member Create (x:'a) = { Head = x; Tail = [] }
member this.Add x = { this with Tail = Seq.append this.Tail [x] }
let a = NonEmptySeq.Create (Event "A")
let b = a.Add (Event "B")
但同样,这些序列是不可变的。如果需要突变,可以使用C#List<'a>
进行类似的操作。在F#中,它称为ResizeArray<'a>
:
type NonEmptyResizeArray<'a> = { Head : 'a; Tail : ResizeArray<'a> } with
static member Create (x:'a) = { Head = x; Tail = ResizeArray [] }
member this.Add x = this.Tail.Add x
let a = NonEmptyResizeArray.Create (Event "A")
a.Add (Event "B")
答案 1 :(得分:5)
我建议您增加功能,而不是为您的类型创建成员-在功能中完成它。例如,这将达到相同的效果,我认为这是更惯用的F#:
type Event = Event of string
type PublishedEvents = EventList of Event * Event list
let create e = EventList (e,[])
let add (EventList(head,tail)) e = EventList(e,head::tail)
let convert (EventList(head,tail)) = head::tail |> Seq.ofList
let myNewList = create (Event "e1")
let myUpdatedList = add myNewList (Event "e2")
let sequence = convert myUpdatedList
val序列:seq = [事件“ e2”;事件“ e1”]
另一方面,如果您的目标是与C#互操作,则在C#方面更容易使用该方法。