N00b pattern matching help needed

27 views
Skip to first unread message

David Harris

unread,
Nov 30, 2015, 2:50:27 PM11/30/15
to F# Discussions

I've been flailing for many many hours on pattern matching & discriminated unions. I'm trying something very simple. What I *want* to write is:

type Hours =
  | Hour24 of int
  | Hour12 of int
 
let (|Hour24|Hour12|) time = 
  match time with   //incomplete pattern match
  | Hour12 time when time>0 && time<=12 ->   Hour12 time
  | Hour24 time when time>12 && time<=24 ->  Hour24 time

let matcht t = 
   match t with 
   | Hour12 t ->  t 
   | Hour24 t ->  t

but this gives an incomplete match error for time. So I try the following :

type Hours =
  | Hour24 of int
  | Hour12 of int
  | Badhour

let (|Hour24|Hour12|) time = 
  match time with 
  | Hour12 time when time>0 && time<=12 ->   Hour12 time
  | Hour24 time when time>12 && time<=24 ->  Hour24 time
  | Badhour  -> Badhour 

let matcht t = 
   match t with 
   | Hour12 t ->  t 
   | Hour24 t ->  t
   | Badhour  -> (*what goes here?*) 


I get why that pattern matching is incomplete but I don't know how to handle matching an error & what would be idiomatic F#.

 

Semyon Grigorev

unread,
Nov 30, 2015, 3:03:11 PM11/30/15
to fsharp-o...@googlegroups.com

Regards,
Semyon Grigorev.

--
--
To post, send email to fsharp-o...@googlegroups.com
To unsubscribe, send email to
fsharp-opensou...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/fsharp-opensource
---
You received this message because you are subscribed to the Google Groups "F# Discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fsharp-opensou...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Isaac Abraham

unread,
Nov 30, 2015, 5:13:35 PM11/30/15
to fsharp-o...@googlegroups.com
I think RoP is a bit overkill here. there are two things you're doing here, one is creating a full DU (with the Type declaration at the top) and an Active Pattern (the function which banana clips). You won't need both of these - either a DU with a normal function that e.g. has a signature int -> Hours or the AP.

To handle the extra case you probably want to use F# option type. So you can have a function that out the hour is less than 12 you return Some Hour12. If less than 24 then Some Hour24. Otherwise return None.

Then you can pattern match e.g.

match convertToHours 16 with
| Some Hour12 -> ...
| Some Hour24 -> ...
| None -> ....

You can use the Option module to help e.g.

convertToHours 16
|> Option.map(fun h -> match h with
    | Hour12 -> ....
    | Hour24 -> ....)

with Option.map it will implicit ignore the None case for you.

From: David Harris
Sent: ‎30/‎11/‎2015 20:50
To: F# Discussions
Subject: N00b pattern matching help needed

Steven Ramsay

unread,
Dec 1, 2015, 3:45:26 AM12/1/15
to fsharp-o...@googlegroups.com
The incomplete match is just a warning, so what you say that you want to write is valid F# and will run.  However, are you sure it is what you want?  I find it a bit odd that the active pattern takes as input something of type Hours and also returns something of type Hours.  

Perhaps you mean to classify integers as hours?  In which case you can remove the Hours type definition and define the active pattern as follows:

let (|Hour24|Hour12|Badhour|) time = 
  if time>0 && time<=12 then Hour12 time
  elif time>12 && time<=24 then Hour24 time
  else Badhour

Or verify that some existing classification is correct?  In which case you can remove the active pattern definition.

let verify (h:Hours) : Hours = 
  match h with 
  | Hour12 time when time>0 && time<=12 ->   Hour12 time
  | Hour24 time when time>12 && time<=24 ->  Hour24 time
  | _ -> Badhour

What you should do when you consume something of type Hours that is of shape Badhour is entirely up to your application.  Maybe you really absolutely know that Badhours never arise, in which case perhaps you can remove this case from the Hours type and live with the incomplete match warning.  Maybe the time comes from user input and so you want to give feedback to the user when they input something bad.  Maybe you want to delegate this to some external error handler and so you throw an exception.

Steven

--
Steven Ramsay


To: fsharp-o...@googlegroups.com
From: isaac....@live.co.uk
Subject: RE: N00b pattern matching help needed
Date: Mon, 30 Nov 2015 23:13:27 +0100

Steven Ramsay

unread,
Dec 1, 2015, 4:00:20 AM12/1/15
to fsharp-o...@googlegroups.com
Actually let me refine something I said in case it causes confusion:

>  takes as input something of type Hours and also returns something of type Hours.  

The active pattern does not literally return something of type Hours (all active patterns return an instance of the Choice type) but the particular active pattern you have defined returns an instance of the choice type that is essentially the same as Hours (and even has the same names for the cases).

Steven

--
Steven Ramsay


Subject: RE: N00b pattern matching help needed
Date: Tue, 1 Dec 2015 08:45:22 +0000

David Harris

unread,
Dec 1, 2015, 4:01:29 AM12/1/15
to F# Discussions, steven...@live.com
your right that it's odd to consume Hours & also return them: I was riffing code at this stage and planning to replace the return expression with something more useful than Hours, but your points are helpful are very helpful. Thanks

David Harris

unread,
Dec 1, 2015, 4:02:52 AM12/1/15
to F# Discussions
What a useful link!! Not heard of Railway orientated programming. Fascinating read thanks. 
Reply all
Reply to author
Forward
0 new messages