Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# how to specify type restriction in recursive discriminated unions

I am trying to define my grammar as a discriminated union. It has two possible types: int and datetime and mathemetical operators of Add and Mul. Add works on int and datetime (as add days in int) Mul works only on int and not on datetime Grammar can be recursive

My grammar looks like

type MyExpression =
|Integer of int
|Date of datetime
|Add of MyExpression * MyExpression
|Mul of MyExpression * MyExpression

I have written a parser (fparsec) that can parse text in my grammar, but I am not sure how to handle the condition that Mul can be recursive but only on Integer.

Is there an option to define this restriction on my MyExpression type or do I have to handle this in my parsed input?

like image 897
abhishek Avatar asked Dec 28 '16 00:12

abhishek


People also ask

How can I recover my Facebook password without code?

To reset your password if you're not logged in to Facebook: Click Forgot Password?. Type the email, mobile phone number, full name or username associated with your account, then click Search. Follow the on-screen instructions.

How can I log into Facebook for free?

Email: You can log in with any email that's listed on your Facebook account. Phone number: If you have a mobile number confirmed on your account, you can enter it here (don't add any zeros before the country code, or any symbols). Username: You can also log in with your username, if you set one up.

Can I download video from Facebook Lite?

You can use the popular fbdown.net website, which allows you to download Facebook videos using your web browser. OR install an app dedicated for the same function. If you're going to download Facebook videos on your Android device regularly, the dedicated Facebook Video Downloader app might be more appealing, though.


2 Answers

The design suggested by Asti would also be my first choice. Depending on your requirements, that may be all you need.

It does, however, also enable you to compile an expression like

Add(Val(System.Console.Out), Val(System.Console.Error))

which is probably not what you want.

Alternatively, you could model expressions like this:

open System

type IntExpression =
| Integer of int
| Mul of IntExpression * IntExpression
| Add of IntExpression * IntExpression

type DateTimeExpression =
| Date of DateTime
| Add of DateTimeExpression * DateTimeExpression

type MyExpression =
| IntExpression of IntExpression
| DateTimeExpression of DateTimeExpression

This is clearly a more verbose type definition, but it does embody the rule that an expression can contain leaf nodes of either integers or DateTime values, and no other values - if that's the rule you want to enforce.

I'm not claiming that this is better; I'm only supplying an alternative.

Usage:

> IntExpression(Mul(IntExpression.Add(Integer(1), Integer(2)),Integer 3));;
val it : MyExpression =
  IntExpression (Mul (Add (Integer 1,Integer 2),Integer 3))
> DateTimeExpression(Add(Date(DateTime.MinValue),Date(DateTime.MinValue)));;
val it : MyExpression =
  DateTimeExpression
    (Add
       (Date 01.01.0001 00:00:00 {Date = 01.01.0001 00:00:00;
                                  Day = 1;
                                  DayOfWeek = Monday;
                                  DayOfYear = 1;
                                  Hour = 0;
                                  Kind = Unspecified;
                                  Millisecond = 0;
                                  Minute = 0;
                                  Month = 1;
                                  Second = 0;
                                  Ticks = 0L;
                                  TimeOfDay = 00:00:00;
                                  Year = 1;},
        Date 01.01.0001 00:00:00 {Date = 01.01.0001 00:00:00;
                                  Day = 1;
                                  DayOfWeek = Monday;
                                  DayOfYear = 1;
                                  Hour = 0;
                                  Kind = Unspecified;
                                  Millisecond = 0;
                                  Minute = 0;
                                  Month = 1;
                                  Second = 0;
                                  Ticks = 0L;
                                  TimeOfDay = 00:00:00;
                                  Year = 1;}))
like image 75
Mark Seemann Avatar answered Sep 27 '22 20:09

Mark Seemann


If you have type based constraints, it may be easier going for a generic approach:

type MyExpression<'t> =
|Val of 't
|Mul of MyExpression<int> * MyExpression<int>
|Add of MyExpression<'t> * MyExpression<'t>

let Integer (x:int) = Val(x)
let Date (x:DateTime) = Val(x)

Usage:

Mul(Integer(1), Integer(2)) //compiles
Mul(Date(DateTime.Now), Date(DateTime.Now)) //error
like image 31
Asti Avatar answered Sep 27 '22 20:09

Asti