Phillip Trelford's Array

POKE 36879,255

Calendar Types

Welcome to the 2015 F# Advent Calendar and one of 2 posts for December 3rd. For last year’s advent calendar I tried to follow the seasonal theme and produced an article on generating snowflakes. This year I thought I’d be more literal and look at producing calendar types using F#’s Type Provider mechanism resurrecting a project from 2014, FSharp.Date.

FSharp.Date

FSharp.Date is a simple F# Type Provider, inspired by VB.Net’s date literal feature,that lets you define dates and time values in F# by pressing dot and selecting only valid values:

2015 December 3rd

Further inspired by the advent calendar theme I’ve added a new feature that lets you visualize the calendar month as a tooltip in your editor:

2015 December Calendar

The source is available on BitBucket or you can download the package from Nuget.

But wait there’s more…

On This Day

That got me thinking, what if you could provide topical information on a particular day direct to the editor, and then I found the BBC news site On This Day.

The web site contains a set of both historically significant and quirky stories from the same day in the past.

First I needed a way of finding an article and scraping the news items from the page.

Thankfully the BBC pages use a uniform URL taking the month and day making it easy to get a specific page:

let getPage (month,day) =
    let date = System.DateTime(2005,month,day)    
    let monthName = date.ToString("MMMM").ToLower()
    let url = sprintf "http://news.bbc.co.uk/onthisday/low/dates/stories/%s/%d/default.stm"
                 monthName date.Day
    use client = new System.Net.WebClient()
    client.DownloadString(url)  

The page’s HTML is not well formed so I resorted to a regular expression to parse the news items:

let getNewsItems html =
    let pattern = """<a href="([^"]*)"><span class="h1">(.*?)</span></a><br>(.*?)<br clear="ALL">"""
    let matches = Regex.Matches(html, pattern, RegexOptions.Singleline)
    let newsItems = [for m in matches -> [for i in 1..m.Groups.Count-1 -> m.Groups.[i].Value]]
    [for newsItem in newsItems do
        match newsItem with
        | [link;title;description] ->
            yield "http://news.bbc.co.uk" + link, title.Trim(), description.Trim().Replace("\n","").Replace("\r","")
        | _ -> ()
    ]

Which returns a list of news items for the specified month and day:

> (12,3)|> getPage |> getNewsItems;;
val it : (string * string * string) list =
  [("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_2698000/2698709.stm",
    "1984: Hundreds die in Bhopal chemical accident",
    "A dense cloud of lethal gas escapes from a chemical factory in the central Indian city of Bhopal, killing hundreds of people.");
   ("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_2519000/2519715.stm",
    "1992: Bomb explosions in Manchester",
    "Emergency services are dealing with casualties at the scene of two bomb blasts in the centre of Manchester.");
   ("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_4119000/4119950.stm",
    "1989: Malta summit ends Cold War",
    "The leaders of the two world superpowers declare an end to the Cold War after two days of storm-lashed talks at the Malta summit.");
   ("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_4119000/4119070.stm",
    "1965: White jury convicts Ku Klux Klansmen",
    "For the first time an all-white jury convicts members of the KKK over the murder of a white civil rights activist Viola Liuzzo.");
   ("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_2519000/2519133.stm",
    "1971: Pakistan intensifies air raids on India",
    "India declares a state of emergency as  airports are hit during a Pakistani attack on the country.");
   ("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_2519000/2519451.stm",
    "1988: Egg industry fury over salmonella claim",
    "Claims by a health minister that eggs contain salmonella are branded alarmist and incorrect.")]
> 

Now to create a type provider.

Creating your own Type Provider

If you’re new to writing your own type provider I’d recommend starting with Michael Newton’s Type Providers From the Ground Up post.

First off we need to reference two F# files from the FSharp.TypeProviders.StarterPack.

Paket

Rather than make a static copy I used Paket, a handy .Net dependency management tool, to reference the files directly from GitHub.

This required a simple paket.dependencies file:

source https://nuget.org/api/v2

github fsprojects/FSharp.TypeProviders.StarterPack src/ProvidedTypes.fsi 
github fsprojects/FSharp.TypeProviders.StarterPack src/ProvidedTypes.fs 

and a paket.references file:

File:ProvidedTypes.fsi
File:ProvidedTypes.fs

With that in place all that’s left to do is run > paket install.

Defining the Type Provider

To create a type provider you need a type with the TypeProvider attribute that inherits from TypeProviderFromNamespaces. For this example I only need a single type OnThisDay which provides the news items via a set of static properties:

[<TypeProvider>]
type OnThisDayProvider (config:TypeProviderConfig) as this = 
   inherit TypeProviderForNamespaces ()

   let getProperties newsItems =
       [for (url, title, description) in newsItems ->
           let property = 
               ProvidedProperty(title, typeof<string>, IsStatic=true,
                  GetterCode=fun _ -> <@@ url @@>)
           property.AddXmlDoc(description)
           property]

   let ns = "FsAdvent"
   let asm = System.Reflection.Assembly.GetExecutingAssembly()
   let today = System.DateTime.Now
   let providedType = ProvidedTypeDefinition(asm, ns, "OnThisDay", Some typeof<obj>)
   do  providedType.AddXmlDoc(today.ToLongDateString())
   do  providedType.AddMembersDelayed(fun () ->             
            (today.Month,today.Day) |> getPage |> getNewsItems |> getProperties
       )
   do  this.AddNamespace(ns, [providedType])

Once it’s built you can reference the type provider and get a list of topical news items for the day directly in your editor:

Tunnel

The selected property returns the URL as the value, which you can easily launch with your default browser using Process.Start:

OnThisDay.``1995: Rogue trader jailed for six years``
|> System.Diagnostics.Process.Start

If you fancy a play the source code is available on GitHub: https://github.com/ptrelford/OnThisDay

Happy holidays!

Introducing FunSharp

FunSharp is a new cross-platform open source graphics library, based on Small Basic’s library, with a typed API crafted for the sharp languages, F# and C#.

Drawing graphics is quick and easy:

GraphicsWindow.FillEllipse(10,10,300,300)

And when you ask FunSharp to draw graphics it will just go and open a window to view it for you:

Purple_Circle

FunSharp provides similar functionality to Python’s PyGame, used for developing games, and Processing used for visual art.

You can call FunSharp immediately from the F# REPL or build full-blown applications using F# and C#.

It’s an ideal library for beginners or anyone who just wants  to get stuff on the screen quickly.

With this in mind FunSharp works seamlessly on Raspberry Pi, Linux and Windows.

Getting Started

If you haven’t already, you’ll need to install F# on your machine, follow these instructions:

  • Linux (for Raspbian follow the Debian instructions)
  • Windows (install Xamarin Studio or Visual Studio)

Get the FunSharp source from GitHub using Clone or Download Zip, then load the FunSharp solution into MonoDevelop or Visual Studio and starting playing with the samples.

Notes:

  • FunSharp is built on Mono’s cross platform graphics libraries Xwt and Gtk# libraries which must be referenced.
  • currently apps must run in 32-bit mode.

Turtles

FunSharp has a Turtle module, which can be used to make fun shapes:

Turtle.X <- 150.
Turtle.Y <- 150.
for i in 0..5..200 do
   Turtle.Move(i)
   Turtle.Turn(90)

Renders:

Turtle_Example

Games

FunSharp can be used to make games quickly and easily. I’ve ported several games written for Small Basic requiring only minor modifications:

Asteroids

Have fun!

Flappy

This week I ran a half-day hands on games development session at the Progressive .Net Tutorials hosted by Skills Matter in London. I believe this was the last conference to be held in Goswell Road before the big move to an exciting new venue.

My session was on mobile games development with F# as the implementation language:


Here’s a quick peek inside the room:


The session tasks were around 2 themes:

  • implement a times table question and answer game (think Nintendo’s Brain Training game)
  • extended a simple Flappy Bird clone

Times table game

The motivation behind this example was to help people:

  • build a simple game loop
  • pick up some basic F# skills

The first tasks , like asking a multiplication question, could be built using F#’s REPL (F# Interactive) and later tasks that took user input required running as a console application.

Here’s some of the great solutions that were posted up to F# Snippets:

To run them, create a new F# Console Application project in Xamarin Studio or Visual Studio and paste in the code (use the Raw view in F# Snippets to copy the code).

Dominic Finn’s source code includes some fun ASCII art too:

// _____ _   _ _____ _____ _____  ______  _  _   _____  _____ _     
//|  __ \ | | |  ___/  ___/  ___| |  ___|| || |_|  _  ||  _  | |    
//| |  \/ | | | |__ \ `--.\ `--.  | |_ |_  __  _| | | || | | | |    
//| | __| | | |  __| `--. \`--. \ |  _| _| || |_| | | || | | | |    
//| |_\ \ |_| | |___/\__/ /\__/ / | |  |_  __  _\ \_/ /\ \_/ / |____
// \____/\___/\____/\____/\____/  \_|    |_||_|  \___/  \___/\_____/
//  

Flappy Bird clone

For this example I sketched out a flappy bird clone using Monogame (along with WinForms and WPF for comparison) with the idea that people could enhance and extend the game:

image

Monogame lets you target multiple platforms including iOS and Android along with Mac, Linux, Windows and even Rapsberry Pi!

The different flavours are available on F# Snippets, simply cut and paste them into an F# script file to run them:

All the samples and tasks are also available in a zip: http://trelford.com/ProgNet15.zip

Have fun!