Re: [MLton] Adding new primitive functions to MLton

Matthew Fluet <[email protected]> Mon, 2 Nov 2020 09:31:12 -0500
Newsgroups gmane.comp.lang.ml.mlton.devel
Message-ID <CAMrhFL7sscU=xVEEDCx_4qfyS8EFMT=R5CMyh5JtKyQh8ACZVA@mail.gmail.com>
--===============2769438932485022876==
Content-Type: multipart/alternative; boundary="000000000000cd8f0805b3209909"

--000000000000cd8f0805b3209909
Content-Type: text/plain; charset="UTF-8"

On Sun, Nov 1, 2020 at 3:26 PM Morten Olsen Lysgaard <[email protected]>
wrote:

> Thanks for the detailed and well thought out answer. It helped me a lot!
> With it I was able to define my primitive and pass it all the way to SXML
> layer.
>
> The MLton code is quite easy to read, and well written compared to other
> compilers I've come across.
>
> To be able to express some of the crucial properties of the time operators
> in a synchronous language, it is required to have a first order program,
> without polymorphism.
> SXML is monomorphic, so my next goal is to get from the SXML to SSA to get
> a monomorphic first-order language.
>
> Right now, my primitives are erroring out with the following message:
> `Ssa.TypeCheck.primApp (Sync_pre(unit) (unit)) in val x_14685: bool = prim
> Sync_pre[unit] (x_14686) in L_0 in main_1`
>
> This error seems to be coming from type checking after the SSA code has
> been generated. But I suspect the real problem lies in the
> `closure-convert.fun` not having any special handling of my new `Sync_pre`
> primitive.
>

Yes.  Primitives without any special handling specified in the closure
conversion pass are assumed to be very simple primitives (e.g.,
`Word<N>_add`), where the input and output types suffice for understanding
the flow.  Since your primitives are completely polymorphic, they need to
explain their behavior.


> I have been trying to figure out what the `ClosureConvert.convertPrimExp`
> function does, but I have still not figured it out.
>
Do you have any details on how it works, and if it could be the root of my
> problem? Or maybe any other places in the conversion from SXML to SSA my
> code could go wrong?
> My `Sync_pre` function should behave like the identity function, `(a ->
> a)`, with respect to the type checking.
>

Well, for closure conversion, we are beyond type checking; now we are
dealing with the semantics of the operations.

If your primitives can be treated as the identity function, then you should
be able to treat them fairly simply.  You would need to include your
primitives in the `primApply` function in `abstract-value.fun` (
https://github.com/MLton/mlton/blob/master/mlton/closure-convert/abstract-value.fun#L391).
Probably you would add a case like

  | Prim.Sync_pre => oneArg ()

With that, you may not need to add anything to the `convertPrimExp`
function of `closure-convert.fun` (
https://github.com/MLton/mlton/blob/master/mlton/closure-convert/closure-convert.fun#L945);
the
default behavior (
https://github.com/MLton/mlton/blob/master/mlton/closure-convert/closure-convert.fun#L1069)
should probably suffice.

-Matthew

On Wed, Oct 28, 2020 at 9:08 PM Matthew Fluet <[email protected]>
> wrote:
>
>> On Mon, Oct 26, 2020 at 6:03 PM Morten Olsen Lysgaard <[email protected]>
>> wrote:
>>
>>> Hi, I am doing some exploratory work on a synchronous programming
>>> language. This is a follow up of my previous email about using an empty
>>> basis.
>>> In that work I have found MLton to have a very good fit as a frontend.
>>>
>>> Like other synchronous languages, eg. lucid synchrone, lustre, there are
>>> primitive time operators. These are:
>>>
>>> pre : forall a. a -> a
>>> when : forall a. a -> Bool -> a
>>> fby : forall a. a -> a -> a
>>>
>>> These functions will have a special meaning for the runtime of my
>>> language, and are thus not possible to implement as library functions. I
>>> would like them to be built into the compiler.
>>>
>>> My first goal is to be able to write code using the functions, and have
>>> them go all the way to core-ml. Not really having the function do anything,
>>> just lexing, parsing, type checking.
>>>
>>> I started hacking in one end, but I quickly realized that I need to
>>> understand more about the architecture and design choices that have been
>>> made for MLton before I add my functions.
>>> I would be very happy for pointers to the relevant places in the MLton
>>> source for my ideas.
>>>
>>> * My thinking is that the functions may not need to be specially handled
>>> during lexing and parsing, because they look like any other function calls
>>> for the lexer/parser. Is this correct?
>>>
>>
>> Most likely, so long as your primitives only depend on the values of
>> their arguments, not on the expressions themselves.  That is, while
>> `Vector_sub` is a primitive, we cannot make `orelse` a primitive, because
>> it depends on short-circuit evaluation, and we cannot make an `assert`
>> primitive, because it wants the text of its argument to be printed on
>> failure.  To put it another way, with a primitive `p` of type `int ->
>> string`, we must be prepared for a source expression `p (1 + 2 + 3)` to be
>> translated to `let val x = 1 + 2 + 3 in p x end` during the early stages of
>> the compiler.
>>
>> * They need to have a "hard-coded" type in the type checker. How to best
>>> achieve this?
>>>
>>
>> They do and they don't.  With respect to the front-end type checking,
>> primitives are imported into the environment with a declared type, which is
>> "trusted" by the type checker.  Somewhat later in the compilation, we type
>> check applications of primitives in the intermediate languages, and there
>> the compiler "knows" the types of primitives.
>>
>>
>>> * How does MLton handle primitive functions like this? Does it use it's
>>> own full fledged expression node for each primitive, is there a special
>>> abstraction in the AST for primitives, or is it using some other solution?
>>>
>>
>> More of the latter: an abstraction in the AST for primitives.
>>
>> Here's the general approach for adding primitives to MLton.
>>
>> Primitives are defined in the compiler via `structure Prim: PRIM`:
>>  - https://github.com/MLton/mlton/blob/master/mlton/atoms/prim.sig
>>  - https://github.com/MLton/mlton/blob/master/mlton/atoms/prim.fun
>>
>> You'd want to add new constructors to the `datatype `a t = ...`
>> declaration and then add cases for the new primitives to most of the
>> functions in the `prim.fun` file.  Importantly, you need to define the
>> `toString` name for the primitives and add them to the `all` value.  This
>> allows the primitives to be imported into the basis library via their
>> name.  Also you need to define the `checkApp` behavior for internal type
>> checking of the primitive.
>>
>> Primitives are imported into source code via the `_prim "name": ty;`
>> form.  See, for example:
>>  -
>> https://github.com/MLton/mlton/blob/master/basis-library/primitive/prim-seq.sml
>>
>> Technically, you don't need to be in the Basis Library implementation to
>> import new primitives; you could define your own .mlb file like the
>> following:
>>
>> ``` sync.mlb:
>> ann
>>   "allowPrim true"
>> in
>>   sync.sml
>> end
>> ```
>>
>> ``` sync.sml:
>> structure Sync =
>> struct
>>   val pre = _prim "Sync_pre": 'a -> 'a;
>>   val when = _prim "Sync_when": 'a -> bool -> 'a;
>>   val fby = _prim "Sync_fby": 'a -> 'a -> 'a;
>> end
>> ```
>>
>> With this, a program that uses `sync.mlb` and then the subsequently
>> exposed primitive operations will type check the source and carry through
>> to the CoreML (and probably even to the XML IR), ultimately erroring out
>> somewhere with an "unexpected primitive" error.
>>
>> You can trace the representation of primitives through the compiler:
>> * AST IR and Parser:
>>  - https://github.com/MLton/mlton/blob/master/mlton/ast/ast-core.sig#L119
>>  - https://github.com/MLton/mlton/blob/master/mlton/ast/ast-core.sig#L153
>>  -
>> https://github.com/MLton/mlton/blob/master/mlton/front-end/ml.grm#L1067
>> * CoreML IR:
>>  -
>> https://github.com/MLton/mlton/blob/master/mlton/core-ml/core-ml.sig#L99
>> * XML/SXML IR:
>>  - https://github.com/MLton/mlton/blob/master/mlton/xml/xml-tree.sig#L94
>>
>> What you do with the primitives beyond this point somewhat depends on how
>> you will implement them.  Most of the MLton supported primitives are simple
>> operations (like Vector_sub or Word32_add), which get carried through the
>> whole compiler and then are handled specially by each code generator,
>> possibly by just making a call to a C function to provide the
>> implementation.  Beware, though, that this may not work well with
>> polymorphic operations.
>>
>> Other primitives are implemented during compilation itself; for example
>> `MLton_equal` (which corresponds to SML's polymorphic equality operation)
>> is expanded to code during the SSA IR optimization passes (
>> https://github.com/MLton/mlton/blob/master/mlton/ssa/poly-equal.fun).
>> We also eliminate some primitives even earlier in the compiler.  For
>> example, the `TopLevel_{get,set}Suffix` primitives are expanded during the
>> XML IR optimization passes (
>> https://github.com/MLton/mlton/blob/master/mlton/xml/implement-suffix.fun
>> ).
>>
>> Best,
>> -Matthew
>> _______________________________________________
>> MLton-devel mailing list
>> [email protected]; [email protected]
>> https://lists.sourceforge.net/lists/listinfo/mlton-devel
>>
> _______________________________________________
> MLton-devel mailing list
> [email protected]; [email protected]
> https://lists.sourceforge.net/lists/listinfo/mlton-devel
>

--000000000000cd8f0805b3209909
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div dir=3D"ltr"><div class=3D"gmail_default" style=3D"fon=
t-family:courier new,monospace;font-size:large"><span style=3D"font-family:=
Arial,Helvetica,sans-serif;font-size:small">On Sun, Nov 1, 2020 at 3:26 PM =
Morten Olsen Lysgaard &lt;<a href=3D"mailto:[email protected]">morten@lysg=
aard.no</a>&gt; wrote:</span><br></div></div><div class=3D"gmail_quote"><bl=
ockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-lef=
t:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>Thanks=
 for the detailed and well thought out answer. It helped me a lot!</div><di=
v>With it I was able to define my primitive and pass it all the way to SXML=
 layer.</div><div><br></div><div>The MLton code is quite easy to read, and =
well written compared to other compilers I&#39;ve come across.<br></div><di=
v><br></div><div></div><div>To be able to express some of the crucial prope=
rties of the time operators in a synchronous language, it is required to ha=
ve a first order program, without polymorphism.</div><div>SXML is monomorph=
ic, so my next goal is to get from the SXML to SSA to get a monomorphic fir=
st-order language.</div><div><br></div><div>Right now, my primitives are er=
roring out with the following message:</div><div><span style=3D"font-family=
:monospace">`Ssa.TypeCheck.primApp (Sync_pre(unit) (unit)) in val x_14685: =
bool =3D prim Sync_pre[unit] (x_14686) in L_0 in main_1`</span></div><div><=
br></div><div>This error seems to be coming from type checking after the SS=
A code has been generated. But I suspect the real problem lies in the <span=
 style=3D"font-family:monospace">`closure-convert.fun`</span> not having an=
y special handling of my new <span style=3D"font-family:monospace">`Sync_pr=
e`</span> primitive.</div></div></blockquote><div><br></div><div class=3D"g=
mail_default" style=3D"font-family:&quot;courier new&quot;,monospace;font-s=
ize:large">Yes.=C2=A0 Primitives without any special handling specified in =
the closure conversion pass are assumed to be very simple primitives (e.g.,=
 `Word&lt;N&gt;_add`), where the input and output types suffice for underst=
anding the flow.=C2=A0 Since your primitives are completely polymorphic, th=
ey need to explain their behavior.</div><div>=C2=A0</div><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div></div><div>I have be=
en trying to figure out what the <span style=3D"font-family:monospace">`Clo=
sureConvert.convertPrimExp`</span> function does, but I have still not figu=
red it out.</div></div></blockquote><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding=
-left:1ex"><div dir=3D"ltr"><div>Do you have any details on how it works, a=
nd if it could be the root of my problem? Or maybe any other places in the =
conversion from SXML to SSA my code could go wrong?<br></div><div>My <span =
style=3D"font-family:monospace">`Sync_pre`</span> function should behave li=
ke the identity function, <span style=3D"font-family:monospace">`(a -&gt; a=
)`</span>, with respect to the type checking.</div></div></blockquote><div>=
<br></div><div class=3D"gmail_default" style=3D"font-family:&quot;courier n=
ew&quot;,monospace;font-size:large">Well, for closure conversion, we are be=
yond type checking; now we are dealing with the semantics of the operations=
.</div><div class=3D"gmail_default" style=3D"font-family:&quot;courier new&=
quot;,monospace;font-size:large"><br></div><div class=3D"gmail_default" sty=
le=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">If you=
r primitives can be treated as the identity function, then you should be ab=
le to treat them fairly=C2=A0simply.=C2=A0 You would need to include your p=
rimitives in the `primApply` function in `abstract-value.fun` (<a href=3D"h=
ttps://github.com/MLton/mlton/blob/master/mlton/closure-convert/abstract-va=
lue.fun#L391">https://github.com/MLton/mlton/blob/master/mlton/closure-conv=
ert/abstract-value.fun#L391</a>).=C2=A0 Probably you would add a case like<=
/div><div class=3D"gmail_default" style=3D"font-family:&quot;courier new&qu=
ot;,monospace;font-size:large"><br></div><div class=3D"gmail_default" style=
=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">=C2=A0 |=
 Prim.Sync_pre =3D&gt; oneArg ()</div><div><br></div><div><div class=3D"gma=
il_default" style=3D"font-family:&quot;courier new&quot;,monospace;font-siz=
e:large">With that, you may not need to add anything to the `convertPrimExp=
` function of `closure-convert.fun` (<a href=3D"https://github.com/MLton/ml=
ton/blob/master/mlton/closure-convert/closure-convert.fun#L945">https://git=
hub.com/MLton/mlton/blob/master/mlton/closure-convert/closure-convert.fun#L=
945</a>);=C2=A0the default behavior (<a href=3D"https://github.com/MLton/ml=
ton/blob/master/mlton/closure-convert/closure-convert.fun#L1069">https://gi=
thub.com/MLton/mlton/blob/master/mlton/closure-convert/closure-convert.fun#=
L1069</a>) should probably suffice.</div><br></div><div><div class=3D"gmail=
_default" style=3D"font-family:&quot;courier new&quot;,monospace;font-size:=
large">-Matthew</div></div><div><br></div><blockquote class=3D"gmail_quote"=
 style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);p=
adding-left:1ex"><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail=
_attr">On Wed, Oct 28, 2020 at 9:08 PM Matthew Fluet &lt;<a href=3D"mailto:=
[email protected]" target=3D"_blank">[email protected]</a>&gt; =
wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=
=3D"ltr"><div dir=3D"ltr"><div style=3D"font-family:&quot;courier new&quot;=
,monospace;font-size:large"><span style=3D"font-family:Arial,Helvetica,sans=
-serif;font-size:small">On Mon, Oct 26, 2020 at 6:03 PM Morten Olsen Lysgaa=
rd &lt;<a href=3D"mailto:[email protected]" target=3D"_blank">morten@lysga=
ard.no</a>&gt; wrote:</span><br></div></div><div class=3D"gmail_quote"><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left=
:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>Hi, I a=
m doing some exploratory work on a synchronous programming language. This i=
s a follow up of my previous email about using an empty basis.<br></div><di=
v>In that work I have found MLton to have a very good fit as a frontend.</d=
iv><div><br></div><div>Like other synchronous languages, eg. lucid synchron=
e, lustre, there are primitive time operators. These are:</div><div><br></d=
iv><div>pre : forall a. a -&gt; a</div><div>when : forall a. a -&gt; Bool -=
&gt; a</div><div>fby : forall a. a -&gt; a -&gt; a</div><div><br></div><div=
>These functions will have a special meaning for the runtime of my language=
, and are thus not possible to implement as library functions. I would like=
 them to be built into the compiler.<br></div><div><br></div><div>My first =
goal is to be able to write code using the functions, and have them go all =
the way to core-ml. Not really having the function do anything, just lexing=
, parsing, type checking.</div><div><br></div><div>I started hacking in one=
 end, but I quickly realized that I need to understand more about the archi=
tecture and design choices that have been made for MLton before I add my fu=
nctions.<br></div><div>I would be very happy for pointers to the relevant p=
laces in the MLton source for my ideas.</div><div><br></div><div>* My think=
ing is that the functions may not need to be specially handled during lexin=
g and parsing, because they look like any other function calls for the lexe=
r/parser. Is this correct?<br></div><div></div></div></blockquote><div><br>=
</div><div><div style=3D"font-family:&quot;courier new&quot;,monospace;font=
-size:large">Most likely, so long as your primitives only depend on the val=
ues of their arguments, not on the expressions themselves.=C2=A0 That is, w=
hile `Vector_sub` is a primitive, we cannot make `orelse` a primitive, beca=
use it depends on short-circuit evaluation, and we cannot make an `assert` =
primitive, because it wants the text of its argument to be printed on failu=
re.=C2=A0 To put it another way, with a primitive `p` of type `int -&gt; st=
ring`, we must be prepared for a source expression `p (1=C2=A0+ 2=C2=A0+ 3)=
` to be translated to `let val x =3D 1=C2=A0+ 2=C2=A0+ 3 in p x end` during=
 the early stages of the compiler.</div></div><div><br></div><blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid=
 rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>* They need to ha=
ve a &quot;hard-coded&quot; type in the type checker. How to best achieve t=
his?</div><div></div></div></blockquote><div><br></div><div><div style=3D"f=
ont-family:&quot;courier new&quot;,monospace;font-size:large">They do and t=
hey don&#39;t.=C2=A0 With respect to the front-end type checking, primitive=
s are imported into the environment with a declared type, which is &quot;tr=
usted&quot; by the type checker.=C2=A0 Somewhat later in the compilation, w=
e type check applications of primitives in the intermediate languages, and =
there the compiler &quot;knows&quot; the types of primitives.</div></div><d=
iv>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0p=
x 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=
=3D"ltr"><div>* How does MLton handle primitive functions like this? Does i=
t use it&#39;s own full fledged expression node for each primitive, is ther=
e a special abstraction in the AST for primitives, or is it using some othe=
r solution?</div></div></blockquote><div><br></div><div style=3D"font-famil=
y:&quot;courier new&quot;,monospace;font-size:large">More of the latter: an=
 abstraction in the AST for primitives.</div><div style=3D"font-family:&quo=
t;courier new&quot;,monospace;font-size:large"><br></div><div style=3D"font=
-family:&quot;courier new&quot;,monospace;font-size:large">Here&#39;s the g=
eneral approach for adding primitives to MLton.</div><div style=3D"font-fam=
ily:&quot;courier new&quot;,monospace;font-size:large"><br></div><div style=
=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">Primitiv=
es are defined in the compiler via `structure Prim: PRIM`:</div><div style=
=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">=C2=A0- =
<a href=3D"https://github.com/MLton/mlton/blob/master/mlton/atoms/prim.sig"=
 target=3D"_blank">https://github.com/MLton/mlton/blob/master/mlton/atoms/p=
rim.sig</a><br></div><div style=3D"font-family:&quot;courier new&quot;,mono=
space;font-size:large">=C2=A0- <a href=3D"https://github.com/MLton/mlton/bl=
ob/master/mlton/atoms/prim.fun" target=3D"_blank">https://github.com/MLton/=
mlton/blob/master/mlton/atoms/prim.fun</a><br></div><div style=3D"font-fami=
ly:&quot;courier new&quot;,monospace;font-size:large"><br></div><div style=
=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">You&#39;=
d want to add new constructors to the `datatype `a t =3D ...` declaration a=
nd then add cases for the new primitives to most of the functions in the `p=
rim.fun` file.=C2=A0 Importantly, you need to define the `toString` name fo=
r the primitives and add them to the `all` value.=C2=A0 This allows the pri=
mitives to be imported into the basis library via their name.=C2=A0 Also yo=
u need to define the `checkApp` behavior for internal type checking of the =
primitive.</div><div style=3D"font-family:&quot;courier new&quot;,monospace=
;font-size:large"><br></div><div style=3D"font-family:&quot;courier new&quo=
t;,monospace;font-size:large">Primitives are imported into source code via =
the `_prim &quot;name&quot;: ty;` form.=C2=A0 See, for example:</div><div s=
tyle=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">=C2=
=A0- <a href=3D"https://github.com/MLton/mlton/blob/master/basis-library/pr=
imitive/prim-seq.sml" target=3D"_blank">https://github.com/MLton/mlton/blob=
/master/basis-library/primitive/prim-seq.sml</a><br></div><div style=3D"fon=
t-family:&quot;courier new&quot;,monospace;font-size:large"><br></div><div =
style=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">Tec=
hnically, you don&#39;t need to be in the Basis Library implementation to i=
mport new primitives; you could define your own .mlb file like the followin=
g:</div><div style=3D"font-family:&quot;courier new&quot;,monospace;font-si=
ze:large"><br></div><div style=3D"font-family:&quot;courier new&quot;,monos=
pace;font-size:large">``` sync.mlb:</div><div style=3D"font-family:&quot;co=
urier new&quot;,monospace;font-size:large">ann</div><div style=3D"font-fami=
ly:&quot;courier new&quot;,monospace;font-size:large">=C2=A0 &quot;allowPri=
m true&quot;</div><div style=3D"font-family:&quot;courier new&quot;,monospa=
ce;font-size:large">in</div><div style=3D"font-family:&quot;courier new&quo=
t;,monospace;font-size:large">=C2=A0 sync.sml</div><div style=3D"font-famil=
y:&quot;courier new&quot;,monospace;font-size:large">end</div><div style=3D=
"font-family:&quot;courier new&quot;,monospace;font-size:large">```</div><d=
iv style=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">=
<br></div><div style=3D"font-family:&quot;courier new&quot;,monospace;font-=
size:large">``` sync.sml:</div><div style=3D"font-family:&quot;courier new&=
quot;,monospace;font-size:large">structure Sync =3D</div><div style=3D"font=
-family:&quot;courier new&quot;,monospace;font-size:large">struct</div><div=
 style=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">=
=C2=A0 val pre =3D _prim &quot;Sync_pre&quot;: &#39;a -&gt; &#39;a;</div><d=
iv style=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">=
=C2=A0 val when =3D _prim &quot;Sync_when&quot;: &#39;a -&gt; bool -&gt; &#=
39;a;</div><div style=3D"font-family:&quot;courier new&quot;,monospace;font=
-size:large">=C2=A0 val fby =3D _prim &quot;Sync_fby&quot;: &#39;a -&gt; &#=
39;a -&gt; &#39;a;</div><div style=3D"font-family:&quot;courier new&quot;,m=
onospace;font-size:large">end</div><div style=3D"font-family:&quot;courier =
new&quot;,monospace;font-size:large">```</div><div style=3D"font-family:&qu=
ot;courier new&quot;,monospace;font-size:large"><br></div><div style=3D"fon=
t-family:&quot;courier new&quot;,monospace;font-size:large">With this, a pr=
ogram that uses `sync.mlb` and then the subsequently exposed primitive oper=
ations will type check the source and carry through to the CoreML (and prob=
ably even to the XML IR), ultimately erroring out somewhere with an &quot;u=
nexpected primitive&quot; error.</div><div style=3D"font-family:&quot;couri=
er new&quot;,monospace;font-size:large"><br></div><div style=3D"font-family=
:&quot;courier new&quot;,monospace;font-size:large">You can trace the repre=
sentation of primitives through the compiler:</div><div style=3D"font-famil=
y:&quot;courier new&quot;,monospace;font-size:large">* AST IR and Parser:</=
div><div style=3D"font-family:&quot;courier new&quot;,monospace;font-size:l=
arge">=C2=A0- <a href=3D"https://github.com/MLton/mlton/blob/master/mlton/a=
st/ast-core.sig#L119" target=3D"_blank">https://github.com/MLton/mlton/blob=
/master/mlton/ast/ast-core.sig#L119</a><br></div><div style=3D"font-family:=
&quot;courier new&quot;,monospace;font-size:large">=C2=A0- <a href=3D"https=
://github.com/MLton/mlton/blob/master/mlton/ast/ast-core.sig#L153" target=
=3D"_blank">https://github.com/MLton/mlton/blob/master/mlton/ast/ast-core.s=
ig#L153</a></div><div style=3D"font-family:&quot;courier new&quot;,monospac=
e;font-size:large">=C2=A0- <a href=3D"https://github.com/MLton/mlton/blob/m=
aster/mlton/front-end/ml.grm#L1067" target=3D"_blank">https://github.com/ML=
ton/mlton/blob/master/mlton/front-end/ml.grm#L1067</a><br></div><div style=
=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">* CoreML=
 IR:</div><div style=3D"font-family:&quot;courier new&quot;,monospace;font-=
size:large">=C2=A0-=C2=A0<a href=3D"https://github.com/MLton/mlton/blob/mas=
ter/mlton/core-ml/core-ml.sig#L99" target=3D"_blank">https://github.com/MLt=
on/mlton/blob/master/mlton/core-ml/core-ml.sig#L99</a></div><div style=3D"f=
ont-family:&quot;courier new&quot;,monospace;font-size:large">* XML/SXML IR=
:</div><div style=3D"font-family:&quot;courier new&quot;,monospace;font-siz=
e:large">=C2=A0-=C2=A0<a href=3D"https://github.com/MLton/mlton/blob/master=
/mlton/xml/xml-tree.sig#L94" target=3D"_blank">https://github.com/MLton/mlt=
on/blob/master/mlton/xml/xml-tree.sig#L94</a></div><div style=3D"font-famil=
y:&quot;courier new&quot;,monospace;font-size:large"><br></div><div style=
=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">What you=
 do with the primitives beyond this point somewhat depends on how you will =
implement them.=C2=A0 Most of the MLton supported primitives are simple ope=
rations (like Vector_sub or Word32_add), which get carried through the whol=
e compiler and then are handled specially by each code generator, possibly =
by just making a call to a C function to provide the implementation.=C2=A0 =
Beware, though, that this may not work well with polymorphic operations.</d=
iv><div style=3D"font-family:&quot;courier new&quot;,monospace;font-size:la=
rge"><br></div><div style=3D"font-family:&quot;courier new&quot;,monospace;=
font-size:large">Other primitives are implemented during compilation itself=
; for example `MLton_equal` (which corresponds to SML&#39;s polymorphic equ=
ality operation) is expanded to code during the SSA IR optimization passes =
(<a href=3D"https://github.com/MLton/mlton/blob/master/mlton/ssa/poly-equal=
.fun" target=3D"_blank">https://github.com/MLton/mlton/blob/master/mlton/ss=
a/poly-equal.fun</a>).=C2=A0 We also eliminate some primitives even earlier=
 in the compiler.=C2=A0 For example, the `TopLevel_{get,set}Suffix` primiti=
ves are expanded during the XML IR optimization passes (<a href=3D"https://=
github.com/MLton/mlton/blob/master/mlton/xml/implement-suffix.fun" target=
=3D"_blank">https://github.com/MLton/mlton/blob/master/mlton/xml/implement-=
suffix.fun</a>).=C2=A0=C2=A0</div><div style=3D"font-family:&quot;courier n=
ew&quot;,monospace;font-size:large"><br></div><div style=3D"font-family:&qu=
ot;courier new&quot;,monospace;font-size:large">Best,</div><div style=3D"fo=
nt-family:&quot;courier new&quot;,monospace;font-size:large">-Matthew</div>=
<div style=3D"font-family:&quot;courier new&quot;,monospace;font-size:large=
"></div></div></div>
_______________________________________________<br>
MLton-devel mailing list<br>
<a href=3D"mailto:[email protected]" target=3D"_blank">MLto=
[email protected]</a>; <a href=3D"mailto:[email protected]"=
 target=3D"_blank">[email protected]</a><br>
<a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" rel=3D=
"noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/listinfo=
/mlton-devel</a><br>
</blockquote></div>
_______________________________________________<br>
MLton-devel mailing list<br>
<a href=3D"mailto:[email protected]" target=3D"_blank">MLto=
[email protected]</a>; <a href=3D"mailto:[email protected]"=
 target=3D"_blank">[email protected]</a><br>
<a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" rel=3D=
"noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/listinfo=
/mlton-devel</a><br>
</blockquote></div></div>

--000000000000cd8f0805b3209909--


--===============2769438932485022876==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline


--===============2769438932485022876==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
MLton-devel mailing list
[email protected]; [email protected]
https://lists.sourceforge.net/lists/listinfo/mlton-devel

--===============2769438932485022876==--