MLElixir - attempting an ML-traditional syntax entirely within the Elixir AST

They tend to be made for some reason, usually to, say, shorten and ease syntax. That is why the caml4p PP exists for OCaml, it has a slightly different syntax, but essentially adds Elixir’y macro’s to OCaml, and been included with it for well over a decade (recently pulled out to a separate source project even). Though there are modern PPX’s that add more pure Elixir style macro’s now via different pass levels (which is how Elixir works too).

I don’t? F# lacks higher modules, it is slower due to compiling to virtual-filled .NET, etc…

Hmm, I’ve not run across that, that’d be interesting to look at. Links? As far as I know it can ‘consume’ simple (non-module’y) OCaml code, but not produce it?

Yeah, a lot of it’s syntax is making it have larger syntax actually, with no greater benefit in readability in my opinion (though perhaps to JS users…).

1 Like

I am still interested about the real world usage of those and how we can write code with it, that is unavoidable easier to read and write as in F-Sharp.

There is .NET Native in the making.

Secondly, there is less significant performance difference, IMHO. Sure, OCaml is speedy like C, while .NET is speedy like Java and thats more than enough for most use cases, yes?

You use Python in your job like millions others do.
And that one is markable slower as F-Sharp. :slight_smile:

Well, not in terms of readability for coders who are used to the OCaml syntax.

While this Reason comparison page to OCaml shows clearly that there are some inconsistencies, who floated into the language over time. Reason · Reason lets you write simple, fast and quality type safe code while leveraging both the JavaScript & OCaml ecosystems.

Such things can confuse a newbie significantly.

Again, the F-Sharp syntax is here the happy medium in my terms.

And its possible to use begin/end same as in OCaml, you dont have to use indendation for local scope.

1 Like

Probably the most simple example would be something like:

module StringMap = Map.Make(String)

That creates a new module of the form of Map specialized for String, and this barely scratches the surface of what it does, but this alone removes all virtual dispatch on these calls, unlike a Map on the .NET VM, and you can do the above for any type anywhere:

type my_type = { blah : integer }
module MyTypeMap = Map.Make(struct
    type t = my_type
    let compare {blah=blah0} {blah=blah1} = compare blah0 blah1
end)

You just need to define the type it uses and an appropriate compare function (The String module already has both, hence why you can just pass it in straight, as would many user types be designed the same way as well).

And this specialization does not just link pointers and a function like F#/.NET/Java do, it literally generates a new module specialized for this specific type, no virtual calls, everything inlineable, more akin to a C++ Template than a Java/.NET Generic.

And even this is still minor compared to what else higher typed modules can do, you can create a whole program in the higher typed modules that reify’s down to a single type of your answer at compile-time, with relative ease.

And this does not even remotely touch on other features OCaml has that F# does not, like ppx_stage, or just any ppx’s at all!

Entirely unrelated. Virtual calls is not a JIT thing that can be removed at native (in fact JIT can often optimize virtual calls better than native, about one of the only things JIT does better I think…), but rather it is when you call a function that you do no know where it is pointing to at runtime, like this pseudo-code:

class Blah {
  public virtual string bloop() { return "base"; }
}
class BlahChild0 {
  public virtual string bloop() { return "child0; }
}
class BlahChild1 {
  public virtual string bloop() { return "child1"; }
}

Blah blah = getBlah();
blah.bloop()

(Wow this forum still has bad color coding…)
It doesn’t matter what language you use, if getBlah() is not local, you don’t know which bloop you will be calling, it is a virtual (or indirect) function call via a mapping on the class object (which is often 2 pointer lookups to acquire as well!). This is the only form of modules that F# has. OCaml on the other hand can specialize entire code paths to specific modules, specialized for each type at each call path via first-class modules. And this is still only scratching the capabilities.

The speed of all is fine in execution, however OCaml compiles significantly faster than all that you mentioned, which makes programming and testing in it significantly faster. So you get both fast compilation and fast execution.

Yeah F# entirely lacks OCaml’s advanced module system and PPX style support, that is pretty poor…

I’m not sure what you mean about tuple types? * is the standard tuple type definition in quite a large variety of languages since the tuple is the base-most prod type, hence you use the prod operator. I’m not sure what is being referenced?

Indentation-based languages need to die off in my opinion, they are extremely brittle in long-term upkeep, Python especially… ^.^;

1 Like
module StringMap = Map.Make(String)
type my_type = { blah : integer }
module MyTypeMap = Map.Make(struct
    type t = my_type
    let compare {blah=blah0} {blah=blah1} = compare blah0 blah1
end)

[quote=“OvermindDL1, post:64, topic:3693”]
You just need to define the type it uses and an appropriate compare function (The String module already has both, hence why you can just pass it in straight, as would many user types be designed the same way as well).[/quote]

Thanks a lot :slight_smile:

OK, thanks a lot again. How is that with this extension:
https://github.com/gusty/FSharpPlus/blob/master/README.md

Oh, interesting. So I think the OCaml compiler is more suitable for native compilation anyway, since much more supported, capable to do “let-it-crash” and more speedy.

There is no reason for .NET Native anymore which I can see now.

Here it works different as for you.

The compilation time of F-Sharp is very speedy?
How ever, the REPL is speedy as in OCaml.

So this advanced module system is related to ppx?
I hope I can one time write such ppx extensions, in order to bring F-Sharps syntax to OCaml.

All these comparisons from here on downwards show me, that OCaml is significantly cluttered, compared to Reason in those aspects.

Also other differences, like this one show me that Reason has cleaned up OCamls syntax significantly.

Well, this is obviously subjective.

To me, indentation is something that any language is sensitive about.
The question is: At commit-time only, so when others are reading it, or also for the syntax checker.

Indendation is there anyhow, so why add additional syntax for something that can solved by it?

Every single piece of unneccessary bloat can go, I get very easly distracted by that.
Especially for newcomers is a a no-go, to add superflous clutter into the syntax, imho.

Of course, there are humans like you, for who the opposite is counting, so I hope for a light><verbose converter in fsharp, in order to please everyone.

By the way: F-Sharp allows more freedom in indendation as Python does.
So you can choose the level of indendation by yourself.

About Python:

Imperative languages become brittle at all, curly brackets all over the place or not.
Imperative programming is brittle by its nature, IMHO.

As far as I can glean from that, that requires quite a lot of indirect calls and virtual ‘classes’ (in the .NET sense).

The OCaml compiler has pluggable back-ends. It comes pre-built with backends for native and a specialized bytecode (great for debugging), but there are others such as to javascript, C, etc… etc…

Many platforms you absolutely, categorically, cannot have a JIT, other than the obvious of iOS that includes systems that have read-only executable memory (a lot of embedded systems). Plus you get the speed boost of initial loading time being a lot faster.

Two different features, unrelated, just two different features that F# lacks that I use both quite heavily.

Cluttered how so? First of all those examples are massively cherry-picked and do not represent real-world code (which if you read through the github issues in full you will find endless examples of how ReasonML has an explosion of parenthesis that people find really difficult to read as just one of many examples, in addition to ambiguities in syntax and more). OCaml’s is entirely unambiguous in every context. You always know when something is a list or a tuple or even an integer or some passed-through type.

I’m not really seeing where. First of all the examples with ;; at the end of the line is entirely stupid (;; is a marker to the repl to ‘run all code entered up till now, right now’, it has no meaning in source code). Second of all, the ‘imperative’ examples is entirely unidiomatic OCaml as imperative code is often entirely not used, and even when used you would NOT want to hide it by not confirming it’s return type (the let () = ... part) as in doing that if you change the return type of the function then you are suddenly not handling it everywhere and can easily miss places that need to handle it now (where the idiomatic ReasonML just kind of silently ignores the change). In many examples they use parenthesis where they are not needed sometimes, and don’t use it other times, they are very inconsistent. Also the heck about the function example, who would ever write ocaml function definitions as anything but the first one?! Also in the ReasonML one what if you have a function that takes a tuple, well now you have multiple embedded parenthesis (this is a common pattern in many cases where you are enforcing uncurrying, doing this in Reason involves lots of double parenthesis instead). Again, it is all mis-informed and cherry picked to make ReasonML look better than it actually is.

I don’t think so, making code indentation sensitive (ala Python or Haskell) means you cannot easy copy/paste code, instead you have to reformat/reindent it into the area it is being pasted in, where with indentation-insensitive languages you can just paste it and run the formatter over it when you save as normal (ocp-indent for OCaml).

Yeah definitely agree there, like ReasonML is full of such bloat, though not as much as Elixir, Elixir’s syntax is very noisy… ^.^;

Curly brackets have nothing to do with imperative anything. Languages that use curly brackets as Scope just use that as such, there are many forms, imperative or not. I prefer how OCaml does scope as 99% of the time it’s only a single expression deep, so absolutely nothing is needed, and the rest of the time you can choose between whichever makes more sense of parenthesis or begin/end. But yes, imperative languages do tend to naturally be brittle in a variety of ways. ^.^;

So I can produce C code with it?

I mean compared to the OCaml one instead.

Therefore, F# offers you active patterns, computation expressions, type providers…

This might be

No doubt about that. This is the reason, why I dont use Reason. :wink:

Might be for you, since you are a professional?

We already chewed that and yeah, I agree with you that they should take it out, I even discussed about that with Chenglou and called it an unfair comparison.

They decide to leave it in. Which means probably, they are scared to look unimportant without such nonsense. Which tells us a story on its own. :slight_smile:

While that truth is obvious, semicolons get used in order to get better information at debugging, Jane Street is using it like that and you already confirmed that sense. :wink:

I got it. Thanks. This is not possible without the insight of someone experienced, so your information is gold. I can just guess otherwise or learn all this hard on my own.
In that perspective, the behaviour of the Reason guys is sad, while well known in the community. Lets say they are too unexperienced in OCaml to know these things. :wink:

You can do that in F-Sharp too?

And here is a web version: https://fantomasweb.apphb.com/

Which is why I dont use it. While I can deal with such noisiness after a while, like in JavaScript. On point, I would say I consider Elixir one of the first choices - if not the first choice - for me when I like to type dynamicly, for which ever reason.

And I still prefer Elixir for Reason, for the curly brackets. Nothing can distract me more as this one, it just seems like coding in a decades old language. Oh wait…

Edit: I just discovered, that I can do dynamic lookup in F-Sharp ^-^

I do not state this.

Yeah, I also love that. Its what conciliates me with it. While 99% are of course overdone by you ;)[quote=“OvermindDL1, post:66, topic:3693”]
and the rest of the time you can choose between whichever makes more sense of parenthesis or begin/end
[/quote]

Yeah, I also love that, since I can choose and choice is always good. :wink:
I love the parenthesis here, since keywords are in my head something that belongs to something completely different, while curly, bracket and common parenthesis are used all over the place to define scope. So it makes more sense to me. :slight_smile:

Oh, yeah. -.-

It’s a large bit ugly, but yep, that’s the ocamlcc project, been a few years since I’ve heard of how it’s doing so it might need some updating, but it’s there and it’s easy enough.

The OCaml what? OCaml does not use a JIT, it is pre-compiled.

Active patterns are doable via PPX in OCaml (or sans ppx but slightly wordy via module functors).
No clue what computation expression is.
Type providers are just a crutch they added to work around the lack of first-class modules.

My current job is the only time I’ve used OCaml professionally, before that it was all just my own code. ^.^;
But that is not what I was referencing, rather the syntax is. Like if you see:

  • [ expr's ] → Always a list
  • expr , expr → Always a tuple
  • [| expr's |] → Always an array
  • expr.name → Always a record access
  • Name.name → Always a module access
  • expr#expr → Always an object access
  • expr;expr → Always returns the second expr (same as erlang!)

Etc… etc…

Yeah I saw those, it rubs me the wrong way. Comparisons should be fair and traditional code.

It’s built for javascripters, you know how they (very general sense) seem to like the syntax fluff, same with Ruby’ers and such.

When not in an indentation sensitive context, otherwise it can mess up, as like in Python or Haskell.

Interesting. The traditional dynamic lookup methods in OCaml is either to use a map of some sort, otherwise Objects are dynamically row-typed, or you can use the introspective functions to pick and peel apart any type in the system to see and access what is inside.

You might not be aware about the .Net Native which I mention.

I mean there is no reason for .NET Native anymore for me, since the native OCaml compiler provides much more. See:

Anyway, so long as .Net Native support for Linux in the form of CoreRT does happen so slow and discriminating towards F#, will I prefer OCaml for native code.

This is all that I am saying.

You can read about them here

In which way?[quote=“OvermindDL1, post:68, topic:3693”]
My current job is the only time I’ve used OCaml professionally
[/quote]

With professional, I mean on a highly skilled level.[quote=“OvermindDL1, post:68, topic:3693”]
Yeah I saw those, it rubs me the wrong way. Comparisons should be fair and traditional code.
[/quote]

Yeah, especially since such a questionable behaviour is one of the main reasons, why I spend years with the community, in order to achieve which I can now communicate within months.

While this is an interesting journey on its own, so I think I am thankful for this. :smiley:

Why Ruby? I see Ruby as comparable sane, syntax wise. Of course again from the view of a newbie.

Well, with code formatting it can. I think such an approach as in Elm would be doable.
Automatic formatting, no matter what. Much better for readability and coding standards.
Plus: Even if this is true and unavoidable - which is not, as shown - would I love to pay that price for a readable syntax. Again: Ocaml is not that harsh in that perspective, since it doesnt effect all the time.

They currently consider it to include for the lenses in F# Plus.

Ah so a monad do notation, what is with the weird name (Microsoft’isms I guess?). There is a super-popular PPX for that in OCaml (that library is brought in just about every sizeable OCaml project). But see, unlike needing language constructs, OCaml tends to prefer libraries (very much like C++ in this way). :slight_smile:

Mostly in it’s verbosity. Even Elixir is super verbose compared to Erlang (excepting Macro’s).

There is a PPX to autogenerate accessors/transformers/etc. as well as a Lens PPX (though most prefer the accessors/transformers as they are far easier to read than lens’s) for OCaml that are also super-popular enough to be in about every sizeable project. ^.^

1 Like

Why needing?

Can you link me something about accessors/transformers, since Google is silent about it?
And also this library, thanks. :slight_smile:

That’s a fantastic question! Why do they do that? ^.^;

There are a few for different types that you may want, since your original bit was about records then I prefer this one:

To paraphrase it’s readme, it can from this record:

type t = {
  dir : [ `Buy | `Sell ];
  quantity : int;
  price : float;
  mutable cancelled : bool;
} [@@deriving fields]

It will generate a whole host of accessors, transformers, and more:

(* Auto-generated *)

(* getters *)
val cancelled : t -> bool
val price     : t -> float
val quantity  : t -> int
val dir       : t -> [ `Buy | `Sell ]

(* setters *)
val set_cancelled : t -> bool -> unit

(* higher order fields and functions over all fields *)
module Fields : sig

  val names : string list

  val cancelled : (t, bool            ) Field.t
  val price     : (t, float           ) Field.t
  val quantity  : (t, int             ) Field.t
  val dir       : (t, [ `Buy | `Sell ]) Field.t

  val create
    :  dir:[ `Buy | `Sell ]
    -> quantity  : int
    -> price     : float
    -> cancelled : bool
    -> t

  val make_creator
    :  dir:      ((t, [ `Buy | `Sell ]) Field.t -> 'a -> ('arg -> [ `Buy | `Sell ]) * 'b)
    -> quantity: ((t, int             ) Field.t -> 'b -> ('arg -> int             ) * 'c)
    -> price:    ((t, float           ) Field.t -> 'c -> ('arg -> float           ) * 'd)
    -> cancelled:((t, bool            ) Field.t -> 'd -> ('arg -> bool            ) * 'e)
    -> 'a -> ('arg -> t) * 'e

  val fold
    :  init:'a
    -> dir      :('a -> (t, [ `Buy | `Sell ]) Field.t -> 'b)
    -> quantity :('b -> (t, int             ) Field.t -> 'c)
    -> price    :('c -> (t, float           ) Field.t -> 'd)
    -> cancelled:('d -> (t, bool            ) Field.t -> 'e)
    -> 'e

  val map
    :  dir      :((t, [ `Buy | `Sell ]) Field.t -> [ `Buy | `Sell ])
    -> quantity :((t, int             ) Field.t -> int)
    -> price    :((t, float           ) Field.t -> float)
    -> cancelled:((t, bool            ) Field.t -> bool)
    -> t

  val iter
    :  dir      :((t, [ `Buy | `Sell ]) Field.t -> unit)
    -> quantity :((t, int             ) Field.t -> unit)
    -> price    :((t, float           ) Field.t -> unit)
    -> cancelled:((t, bool            ) Field.t -> unit)
    -> unit

  val for_all
    :  dir      :((t, [ `Buy | `Sell ]) Field.t -> bool)
    -> quantity :((t, int             ) Field.t -> bool)
    -> price    :((t, float           ) Field.t -> bool)
    -> cancelled:((t, bool            ) Field.t -> bool)
    -> bool

  val exists
    :  dir      :((t, [ `Buy | `Sell ]) Field.t -> bool)
    -> quantity :((t, int             ) Field.t -> bool)
    -> price    :((t, float           ) Field.t -> bool)
    -> cancelled:((t, bool            ) Field.t -> bool)
    -> bool

  val to_list
    :  dir      :((t, [ `Buy | `Sell ]) Field.t -> 'a)
    -> quantity :((t, int             ) Field.t -> 'a)
    -> price    :((t, float           ) Field.t -> 'a)
    -> cancelled:((t, bool            ) Field.t -> 'a)
    -> 'a list

  val map_poly : ([< `Read | `Set_and_create ], t, 'a) Field.user -> 'a list

  (** Functions that take a record directly *)
  module Direct : sig

      val fold
        :  t
        -> init:'a
        -> dir      :('a -> (t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> 'b)
        -> quantity :('b -> (t, int             ) Field.t -> t -> int              -> 'c)
        -> price    :('c -> (t, float           ) Field.t -> t -> float            -> 'd)
        -> cancelled:('d -> (t, bool            ) Field.t -> t -> bool             -> 'e)
        -> 'e

      val map
        :  t
        -> dir      :((t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> [ `Buy | `Sell ])
        -> quantity :((t, int             ) Field.t -> t -> int              -> int)
        -> price    :((t, float           ) Field.t -> t -> float            -> float)
        -> cancelled:((t, bool            ) Field.t -> t -> bool             -> bool)
        -> t

      val iter
        :  t
        -> dir      :((t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> unit)
        -> quantity :((t, int             ) Field.t -> t -> int              -> unit)
        -> price    :((t, float           ) Field.t -> t -> float            -> unit)
        -> cancelled:((t, bool            ) Field.t -> t -> bool             -> unit)
        -> unit

      val for_all
        :  t
        -> dir      :((t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> bool)
        -> quantity :((t, int             ) Field.t -> t -> int              -> bool)
        -> price    :((t, float           ) Field.t -> t -> float            -> bool)
        -> cancelled:((t, bool            ) Field.t -> t -> bool             -> bool)
        -> bool

      val exists
        :  t
        -> dir      :((t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> bool)
        -> quantity :((t, int             ) Field.t -> t -> int              -> bool)
        -> price    :((t, float           ) Field.t -> t -> float            -> bool)
        -> cancelled:((t, bool            ) Field.t -> t -> bool             -> bool)
        -> bool

      val to_list
        :  t
        -> dir      :((t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> 'a)
        -> quantity :((t, int             ) Field.t -> t -> int              -> 'a)
        -> price    :((t, float           ) Field.t -> t -> float            -> 'a)
        -> cancelled:((t, bool            ) Field.t -> t -> bool             -> 'a)
        -> 'a list
        
      val set_all_mutable_fields : t -> cancelled:bool -> unit
    end

end

In addition it allows some other libraries to easily introspect into the given records as well.

Let’s break up each part into why it’s useful:

Getters

val cancelled : t -> bool
val price     : t -> float
val quantity  : t -> int
val dir       : t -> [ `Buy | `Sell ]

The usefulness of this should be obvious, let’s you pass pre-made accessor functions around (think the .blah calls of Elm). :slight_smile:

Setters

val set_cancelled : t -> bool -> unit

If you have any fields in it that are mutable then this gives you convenient pre-made functions that you can pass around to update them (great for callbacks!).

Higher order fields and functions over all fields

module Fields : sig

This is a submodule of various useful and repeatable calls. Note that this module can be passed as a first-class module to functions to be used as a callback module (following the standard naming conventions for ease of compatibility), think of it like a static-lens-on-steroids (able to mess with all fields, or some, or whatever):

Field names

  val names : string list

A string list of field names, a very useful and efficient helper for introspection (often used by json generator libraries as just one example of many).

Field introspection objects

  val cancelled : (t, bool            ) Field.t
  val price     : (t, float           ) Field.t
  val quantity  : (t, int             ) Field.t
  val dir       : (t, [ `Buy | `Sell ]) Field.t

Very easy to use field introspection objects, significantly easier to use than raw reflection and can be used as Lens’s to boot!

create

  val create
    :  dir:[ `Buy | `Sell ]
    -> quantity  : int
    -> price     : float
    -> cancelled : bool
    -> t

Just a simple helper function that you can pass around to construct a record via passed-in arguments, great again for passing to callbacks!

make_creator

  val make_creator
    :  dir:      ((t, [ `Buy | `Sell ]) Field.t -> 'a -> ('arg -> [ `Buy | `Sell ]) * 'b)
    -> quantity: ((t, int             ) Field.t -> 'b -> ('arg -> int             ) * 'c)
    -> price:    ((t, float           ) Field.t -> 'c -> ('arg -> float           ) * 'd)
    -> cancelled:((t, bool            ) Field.t -> 'd -> ('arg -> bool            ) * 'e)
    -> 'a -> ('arg -> t) * 'e

This takes a set of functions, one-per-field-of-the-record, and finally it returns a function that takes an argument, that argument is passed to each callback function to construct the needed value for that field, where finally the record is full returned, each function able to pass along an accumulator to hold state. :slight_smile:

fold / map / iter / for_all / exists

  val fold
    :  init:'a
    -> dir      :('a -> (t, [ `Buy | `Sell ]) Field.t -> 'b)
    -> quantity :('b -> (t, int             ) Field.t -> 'c)
    -> price    :('c -> (t, float           ) Field.t -> 'd)
    -> cancelled:('d -> (t, bool            ) Field.t -> 'e)
    -> 'e

  val map
    :  dir      :((t, [ `Buy | `Sell ]) Field.t -> [ `Buy | `Sell ])
    -> quantity :((t, int             ) Field.t -> int)
    -> price    :((t, float           ) Field.t -> float)
    -> cancelled:((t, bool            ) Field.t -> bool)
    -> t

  val iter
    :  dir      :((t, [ `Buy | `Sell ]) Field.t -> unit)
    -> quantity :((t, int             ) Field.t -> unit)
    -> price    :((t, float           ) Field.t -> unit)
    -> cancelled:((t, bool            ) Field.t -> unit)
    -> unit

  val for_all
    :  dir      :((t, [ `Buy | `Sell ]) Field.t -> bool)
    -> quantity :((t, int             ) Field.t -> bool)
    -> price    :((t, float           ) Field.t -> bool)
    -> cancelled:((t, bool            ) Field.t -> bool)
    -> bool

  val exists
    :  dir      :((t, [ `Buy | `Sell ]) Field.t -> bool)
    -> quantity :((t, int             ) Field.t -> bool)
    -> price    :((t, float           ) Field.t -> bool)
    -> cancelled:((t, bool            ) Field.t -> bool)
    -> bool

Generic transformation functions, like the ones in Elixir except they operate over each field, they are all fantastic helpers and are very often used when this module is used as a first-class module witness.

to_list

  val to_list
    :  dir      :((t, [ `Buy | `Sell ]) Field.t -> 'a)
    -> quantity :((t, int             ) Field.t -> 'a)
    -> price    :((t, float           ) Field.t -> 'a)
    -> cancelled:((t, bool            ) Field.t -> 'a)
    -> 'a list

A reduction function that reduces to a uni-typed list, great to use to be able to pass a record to other things for transformations.

map_poly

  val map_poly : ([< `Read | `Set_and_create ], t, 'a) Field.user -> 'a list

A polymorphic mapping function that returns polymorphic variants of the requisite field information.

Direct

  module Direct : sig

      val fold
        :  t
        -> init:'a
        -> dir      :('a -> (t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> 'b)
        -> quantity :('b -> (t, int             ) Field.t -> t -> int              -> 'c)
        -> price    :('c -> (t, float           ) Field.t -> t -> float            -> 'd)
        -> cancelled:('d -> (t, bool            ) Field.t -> t -> bool             -> 'e)
        -> 'e

      val map
        :  t
        -> dir      :((t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> [ `Buy | `Sell ])
        -> quantity :((t, int             ) Field.t -> t -> int              -> int)
        -> price    :((t, float           ) Field.t -> t -> float            -> float)
        -> cancelled:((t, bool            ) Field.t -> t -> bool             -> bool)
        -> t

      val iter
        :  t
        -> dir      :((t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> unit)
        -> quantity :((t, int             ) Field.t -> t -> int              -> unit)
        -> price    :((t, float           ) Field.t -> t -> float            -> unit)
        -> cancelled:((t, bool            ) Field.t -> t -> bool             -> unit)
        -> unit

      val for_all
        :  t
        -> dir      :((t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> bool)
        -> quantity :((t, int             ) Field.t -> t -> int              -> bool)
        -> price    :((t, float           ) Field.t -> t -> float            -> bool)
        -> cancelled:((t, bool            ) Field.t -> t -> bool             -> bool)
        -> bool

      val exists
        :  t
        -> dir      :((t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> bool)
        -> quantity :((t, int             ) Field.t -> t -> int              -> bool)
        -> price    :((t, float           ) Field.t -> t -> float            -> bool)
        -> cancelled:((t, bool            ) Field.t -> t -> bool             -> bool)
        -> bool

      val to_list
        :  t
        -> dir      :((t, [ `Buy | `Sell ]) Field.t -> t -> [ `Buy | `Sell ] -> 'a)
        -> quantity :((t, int             ) Field.t -> t -> int              -> 'a)
        -> price    :((t, float           ) Field.t -> t -> float            -> 'a)
        -> cancelled:((t, bool            ) Field.t -> t -> bool             -> 'a)
        -> 'a list
        
      val set_all_mutable_fields : t -> cancelled:bool -> unit
    end

A sub module inside this sub module, it adds a lot of transformation functions that operate over the record in it’s first call position, I.E. just a set of helpers from the above with arguments shuffled to make different use-cases easier.

 

And this is just one of many many PPX’s for OCaml.

Like this one is like the record one above, but for variants (with variant-specific things and without record specific things):

And a matcher view transformer for transforming match expressions (Hmm, I just realized this is very much like Active patterns in F#, I wonder if this is where F# got its idea from…):

There is of course the all-popular deriving PPX that let’s other PPX’s make easy deriving integration (deriving is similar to Elixir’s @derive definition), often used for JSON generation, XML, auto-comparisons, etc… etc…:

A great PPX to reduce type declarations when you are needing to extend the functions of a type you do not control:

And a PPX that adds Elixir-like macro’s (it even adds a quote-like form with unquote too! It’s quote is called code and unquote is called e, though the macros are not hidden in the syntax as it is in Elixir, they require an explicit declaration to reify them into inline code, which I actually quite prefer to be honest… less magic unlike Elixir):

That one works like (using the unless macro in the Elixir Getting Started Macro Guide converted to OCaml):

let unless clause do_code =
  [%code
    if [%e clause]
    then ()
    else [%e do_code]
  ]

let test = Ppx_stage.run (unless [%code false] [%code print_string "vwhoo!"])

Of course as stated before the macro calls are not just magic function-like calls like in Elixir, you have to ‘initiate’ it by calling run on it, which actually inlines it at compile-time in place, so the above just ends up becoming:

let test = if false then () else print_string "vwhoo!"

It is designed to be a speed boost, not something you should really use (macro’s are discouraged in OCaml overall).

If you really really want function-like macro’s then you’ll use the caml4p front-end for OCaml (it’s another library, a PP library this time, kind of like reason but more powerful and different syntax, it used to be built in to OCaml but it was pulled out into a library many many versions ago), but that is generally discouraged for general work, and yet it is still very used, so eh… I prefer the stage style as I prefer explicitness even if more verbose (that just makes sure that I’m only using it where it really matters then).

2 Likes

I mean, what is the negative impact on that in your opinion?

I will study this, thanks a lot ^^

In Akka.NET, you can support self healing systems, so as in upcoming MCOCaml and Erlang`s BEAM.

It pollutes the language, making more forms potentially ambiguous in addition to making it more difficult to extend to something truly unique later.[quote=“ShalokShalom, post:73, topic:3693”]
In Akka.NET, you can support self healing systems, so as in upcoming MCOCaml and Erlang`s BEAM.
[/quote]

Akka and Akka.NET are just libaries, they can already be supported on the systems, or Python, or C++, or whatever languages want to implement such a similar library. The self-healing aspect has absolutely nothing to do with the language.

1 Like

Well, I am informed that they are “just” libraries - the thing is, I can use it.
Self healing actor model is possible on F-Sharp and this is whats important.

What do you think about ZeroMQ?
http://zeromq.github.io/fszmq/tutorial.html

And one more:
https://grpc.io/

Akka.NET seems to suffer from the same issues you always find when not having a proper scheduler and trying to run Erlang-like systems, no? According to the docs it uses the .NET thread pool as it is and hopes it’s good enough. You can still just starve it by having long running things and then it’ll struggle to add more threads.

Case in point?

Having to worry about not blocking is not an acceptable solution, IMO.

1 Like

Precisely, it has no preemptive or even cooporative scheduling that extends past Native OS Threads last I saw.

Though C++ has cooperative greenthreads that can swap on IO. ^.^

1 Like

How will that be in OCaml?

Similar to how it is in Erlang actually when MCOCaml lands. :slight_smile:

MCOCaml uses algebraic effects to basically control a given context, and thus any functions it controls it will be able to pre-empt at those call points (just like how Erlang can only pre-empt at function calls, generally only external function calls as module-internal calls often get optimized out depending on size, same in OCaml).

C++'s greenthreads (lots of libraries for it) can swap on any function they control as well, though not ‘quite’ to the same detail, but enough for the majority of cases excepting tight loops or so, however you can also have it spawn more system threads to handle the greenthreads if some start taking too much time and use work stealing to steal them off other threads.

1 Like

While I guess the GC stays the same?

OCaml’s GC is more generic sadly, though the fact it can generate significantly better code than the BEAM due to knowing the types of things means it will outperform the BEAM in most situations anyway.

1 Like