Skip to content
Bryan Edds edited this page Jul 25, 2023 · 26 revisions

Sometimes people find custom operators to be a stumbling block when using new F# APIs. We have worked hard to try to minimize the amount of custom operators users need to learn to use Nu. However, in order to make the API practical to succinctly author code with, we had to keep some. Here's a cheat-sheet of Nu's operators, starting with the operators you should familiarize yourself with first.

Operators for MMCC

    /// Define a property initializer.
    let (==) (lens : Lens<'a, 's>) (value : 'a) : InitializerContent =
        PropertyContent (PropertyContent.make true lens value)

The == operator will initialize the property of a simulant with some unchanging value in an MMCC context.

    /// Define a property synchronizer.
    let (:=) (lens : Lens<'a, 's>) (value : 'a) : InitializerContent =
        PropertyContent (PropertyContent.make false lens value)

The := operator will keep the property of a simulant synchronized with a changing value in an MMCC context. You might think of it like a data binding if you're familiar with MVC terminology.

    /// Define an event signal.
    let (=>) (eventAddress : 'a Address) (signal : Signal) : InitializerContent =
        EventSignalContent (Address.generalize eventAddress, signal)

The => operator will cause an event to produce a signal (either a Message or a Command) that can be consumed in an MMCC context.

    /// Define an event handler.
    let (=|>) (eventAddress : 'a Address) (callback : Event<'a, 's> -> Signal) : InitializerContent =
        EventHandlerContent (PartialEquatable.make (Address.generalize eventAddress) (fun (evt : Event) -> callback (Event.specialize evt) :> obj))

The =|> operator will cause an event to produce a signal (either a Message or a Command) that can be consumed in an MMCC context. Additionally, it allows the Event<'a, 's> value or its data to be passed into the constructed signal.

Operators for Composing Addresses

        /// Concatenate two addresses of the same type.
        static member (-|-) (address : 'a Address, address2 : 'a Address) = Address.acat address address2

        /// Concatenate two addresses, taking the type of first address.
        static member (->-) (address : 'a Address, address2 : obj Address) = Address.acatf address address2

        /// Concatenate two addresses, forcing the type of first address.
        static member (-->) (address : 'a Address, address2 : 'b Address) = Address.acatff address address2

        /// Concatenate two addresses, taking the type of the second address.
        static member (-<-) (address : obj Address, address2 : 'b Address) = Address.acats address address2

        /// Concatenate two addresses, forcing the type of second address.
        static member (<--) (address : 'a Address, address2 : 'b Address) = Address.acatsf address address2

These are the various operators used to conveniently construct new addresses. Generally, if you stick to the MMCC API, you won't have to compose address much yourself if at all.

    /// Concatenate an address with a simulant's address, forcing the type of first address.
    static member (-->) (address : 'a Address, simulant : #Simulant) =
        if isNull (group :> obj) then Address.anonymize address else acatff address simulant.SimulantAddress

Operators for Constructing Simulant Handles

The --> operator is a convenience overload for construct new addresses from simulants directly. You will use this when defining new types of events for your simulants like so -

    [<RequireQualifiedAccess>]
    module Events =
        let ItemSelect = stoa<string> "Item/Select/Event"

    type Entity with
        member this.ItemSelectEvent = Events.ItemSelect --> this
    static member (/) (simulant : #Simulant, childName) =
        Simulant (atoa<Group, Entity> group.GroupAddress --> ntoa entityName)

The / operator overload makes it easy to construct hierarchies of simulant handles like so -

[<RequireQualifiedAccess>]
module Simulants =
    let Screen = Nu.Screen "Screen"
    let Group = Screen / "Group"
    let Elmario = Group / "Elmario"
Clone this wiki locally