Reputation: 1858
Learning to use F#, and I'm trying to get familiar with the match expression. I expect the below code to pick two consecutive days out of the week, the current day and the day after. It only picks out the current day. What am I missing here?
DayOfWeek array:
let days = [|DayOfWeek.Sunday, true;
DayOfWeek.Monday, false;
DayOfWeek.Tuesday, true;
DayOfWeek.Wednesday, true;
DayOfWeek.Thursday, true;
DayOfWeek.Friday, true;
DayOfWeek.Saturday, true;|]
Match expression:
let curDate = DateTime.Now
let validDates =
[
for i in days do
match i with
| day, true ->
match day with
| x when int x = int curDate.DayOfWeek ||
int x > int curDate.DayOfWeek
&& int x - int curDate.DayOfWeek = 1 ->
yield
x
| _ -> ()
|_ -> ()
]
Upvotes: 0
Views: 417
Reputation: 590
For me, the difficulty is with using pattern matching.
Here is how I would do it without, allowing you to take any number of days, not just two.
open System
let next count days day =
seq { while true do yield! days } // make the days array infinite
|> Seq.skipWhile (fun (d, _) -> d <> day) // skip until we find our day
|> Seq.filter (fun (_, incl) -> incl) // get rid of 'false' days
|> Seq.take count // take the next 'count' of days
|> Seq.map (fun (d, _) -> d) // we only care about the day now, so a simple map gets rid of the boolean
Using your array of days, I get the following:
DayOfWeek.Sunday
|> next 2 days
val it : seq<DayOfWeek> = seq [Sunday; Tuesday]
and
DayOfWeek.Thursday
|> next 3 days
val it : seq<DayOfWeek> = seq [Thursday; Friday; Saturday]
and
DayOfWeek.Sunday
|> next 10000 days
|> Seq.iter (printfn "%A")
Well, I'm not going to print what this one does, you'll just have to use your imagination. :)
I hope that helps!
Edit I made it handle an infinite number of days.
Upvotes: 1
Reputation: 52290
I think you can write this a lot easier by using the Enum-caps of F#/.net:
open System;;
let weekdayAfter (day : DateTime) : DayOfWeek =
int day.DayOfWeek
|> (fun i -> (i+1) % 7)
|> Microsoft.FSharp.Core.LanguagePrimitives.EnumOfValue<_, _>
let today_and_tomorrow =
let today = DateTime.Today
(today.DayOfWeek, weekdayAfter today)
And if you really want to use pattern-matching then why not go with the readable/obvious solution:
let dayAfter (day : DateTime) =
match day.DayOfWeek with
| DayOfWeek.Sunday -> DayOfWeek.Monday
| DayOfWeek.Monday -> DayOfWeek.Tuesday
| DayOfWeek.Tuesday -> DayOfWeek.Wednesday
| DayOfWeek.Wednesday -> DayOfWeek.Thursday
| DayOfWeek.Thursday -> DayOfWeek.Friday
| DayOfWeek.Friday -> DayOfWeek.Saturday
| DayOfWeek.Saturday -> DayOfWeek.Sunday
| _ -> failwith "should never happen"
Upvotes: 1
Reputation: 258
Your solution seems extremely convoluted to me, and like others have mentioned it only works if the underlying int value of tomorrow's DayOfWeek is one greater than today's. As you know, the week is a cycle so that logic won't always hold true. I don't want to spoonfeed, but there is a much easier solution:
let today = DateTime.Now.DayOfWeek
let days = [|DayOfWeek.Sunday, true;
DayOfWeek.Monday, false;
DayOfWeek.Tuesday, true;
DayOfWeek.Wednesday, true;
DayOfWeek.Thursday, true;
DayOfWeek.Friday, true;
DayOfWeek.Saturday, true;|]
let today_and_tomorrow =
let idx_today = Array.findIndex (fun (day, _) -> day = today) days
days.[idx_today], days.[idx_today + 1 % days.Length]
Upvotes: 3