F # последовательность хотя бы с одним элементом - PullRequest
0 голосов
/ 03 июля 2018

Новичок в 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])

Теперь он жалуется, что "this" несовместимо с seq ..., что меня сейчас смущает, так как в нескольких строках над ним написано EventList of seq<Event> ... так что, думаю, мне нужно как-то преобразовать EventList обратно на seq<Event>, поэтому я могу использовать Seq.append?

let convertFunction (eventList:PublishedEvents) : seq<Event> = ???

Но я понятия не имею, как это сделать.

Я даже иду в правильном направлении? Лучше ли для этого имитировать класс C # с помощью вспомогательного поля? Или я что-то упустил?

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Я предлагаю вам пойти еще функциональнее и не создавать членов для ваших типов - сделайте это в ваших функциях. Например, это могло бы достичь того же, и я бы сказал, что это более идиоматично. 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 #.

0 голосов
/ 03 июля 2018

Фактическая последовательность событий заключена в EventList дискриминируемый случай объединения.

Вы можете развернуть его и перемотать так:

type PublishedEvents with
    member this.add(event:Event) =
        match this with
        | EventList events -> Seq.append events [event] |> EventList

Однако я должен сначала усомниться в ценности создания этого типа PublishedEvents, если это всего лишь один EventList случай, содержащий последовательность, которая требует от вас повторять или разворачивать значения.

Также имейте в виду, что этот метод add не меняет существующий PublishedEvents. Он создает новый с новой последовательностью событий из-за способа, которым работает Seq.append, потому что seq<'a> на самом деле является просто именем F # для System.Collections.Generic.IEnumerable<'a>).

Кроме того, ваш подход не предотвращает создание непустой последовательности событий. 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")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...