Re: datatype constructor as syntax

Phil Clayton <[email protected]>
Newsgroups gmane.comp.lang.ml.mlton.user
Message-ID <[email protected]>
> 20/03/14 13:02, Matthew Fluet wrote:
>> On Wed, Mar 19, 2014 at 7:46 PM, Phil Clayton <[email protected]> wrote:
>>> 19/03/14 23:37, Phil Clayton wrote:
>>>> 19/03/14 19:16, Matthew Fluet wrote:
>>>>> On Tue, Dec 31, 2013 at 3:47 AM, Florian Weimer <[email protected]> wrote:
>>>>>> * Henry Cejtin:
>>>>>>
>>>>>>> Sorry,  I  thought  I  was  being  clever,  but  if  you look at Andreas
>>>>>>> Rossberg's Defects in the Revised Definition of Standard ML
>>>>>>>         http://www.ps.uni-saarland.de/Publications/documents/Rossberg_DefectsSML.pdf
>>>>>>> you will see that he points out that rule 126 of the  dynamic  semantics
>>>>>>> implies  that  this  should really give you a bind exception at runtime.
>>>>>>> This was fixed (meaning you get the in MLton way back in 2001 to give an
>>>>>>> error at compile time.
>>>>>>
>>>>>> Curiously, the fun-based approach
>>>>>>
>>>>>>       datatype mytype = foo | bar of int
>>>>>>       fun bar _ = ()
>>>>>>       val bar = 23
>>>>>>
>>>>>> still runs without raising an exception when compiled with MLton.
>>>>>
>>>>> That seems to be an oversight.
>>>>
>>>> Perhaps I missed the point here but I'm hoping that it's intentional
>>>> that MLton allows the status of a constructor id to be overwritten by a
>>>> fun binding.  I am relying on code as follows to create a value NONE:
>>>>
>>>>       local
>>>>         fun NONE () = <expression>
>>>>       in
>>>>         val NONE = NONE ()
>>>>       end
>>>>
>>>> Note that this does not create an unreferenced id, which avoids spurious
>>>> warnings from such checks, for example, using Poly/ML with
>>>>       PolyML.Compiler.reportUnreferencedIds := true;
>>>>
>>>> If this isn't allowed, how should a value called NONE be created?
>>>
>>> Responding to myself:
>>>
>>>      local
>>>        structure S : sig val NONE : int option end = struct open Option end
>>>        open S
>>>      in
>>>        val NONE = <expression>
>>>      end
>>>
>>> Yuk!  Is there anything nicer?
>>
>> Ah, that is clever.  The signature exactly specifies the
>> constructor/non-constructor status of the identifier.
>>
>> You could adopt a slightly more generic approach like:
>>
>> local
>>     structure S : sig type t val NONE : t end = struct datatype t = NONE end
>>     open S
>> in
>>     val NONE = <expression>
>> end
>>
>> which should work whether or not NONE is an in-scope constructor and,
>> if it is in scope, without needing to know its type.

Your suggestion works much better.  My issue with the example I gave was 
dependence on context - the type, in particular.

The motivation for a transformation on the concrete syntax tree of
   val <id> = <exp>
that is independent of context is to have a simple algorithm that a code 
generator can use to rebind constructor names as values if needed, given 
a list of possible constructor names.


>> The disadvantage of this approach is that one cannot use a "structure"
>> declaration within a "let" expression.

That probably wouldn't be a practical issue for me.  However, I'll 
probably stick with the fun method whilst it is supported in MLton as 
this works in Poly/ML and SML/NJ too.


20/03/14 13:09, Andreas Rossberg wrote:
> While I also appreciate the possibility of playing tricks like these, I
> don't think it's a good idea to rebind an identifier as fundamental as
> NONE in real code, no matter how easy or hard it is.

Sure - I would never advocate this in hand-written SML!  The situation 
arises in bindings to an existing library, where the existing names and 
the SML abstraction result in a value called 'NONE', for example:

 
https://developer.gnome.org/gtk3/3.10/gtk3-Standard-Enumerations.html#GtkJunctionSides

   signature GTK_JUNCTION_SIDES =
     sig
       eqtype t
       include BIT_FLAGS where type flags = t
       val NONE : t               <----------------------
       val CORNERTOPLEFT : t
       val CORNERTOPRIGHT : t
       val CORNERBOTTOMLEFT : t
       val CORNERBOTTOMRIGHT : t
       val TOP : t
       val BOTTOM : t
       val LEFT : t
       val RIGHT : t
       ...
     end

The SML trickery is hidden inside the bindings code so I don't see any 
detraction from a user perspective.  The alternative would be a 
different name e.g. NONE', which has obvious detractions, e.g. doesn't 
match existing documentation and will catch programmers out.

In the case of flags, arguably NONE isn't required because it is 
possible to write
   Gtk.JunctionSides.flags []
but I've just settled on simple traceability to the original library and 
documentation.  There are non-flag examples too:

   signature GTK_RESPONSE_TYPE =
     sig
       type t = LargeInt.int
       val NONE : t               <----------------------
       val REJECT : t
       val ACCEPT : t
       val DELETEEVENT : t
       val OK : t
       val CANCEL : t
       val CLOSE : t
       val YES : t
       val NO : t
       val APPLY : t
       val HELP : t
     end

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and their
applications. Written by three acclaimed leaders in the field,
this first edition is now available. Download your free book today!
http://p.sf.net/sfu/13534_NeoTech
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.