Inside F#

Brian's thoughts on F# and .NET

Using VS2010 to edit F# source code (and a little LOGO EDSL)

Posted by Brian on April 15, 2010

I made another F# screencast.  This one covers features of the Visual Studio editor; the backdrop is some code for doing LOGO (turtle graphics).  The screencast is available here (a couple clicks to download; I’m still working on some new file hosting to try to embed video).  It’s an 11-minute video that covers these topics:

  • Syntax highlighting (colors/fonts/sizes)
  • Intellisense (auto-complete, parameter help)
  • Squiggles (errors, warnings, navigation)
  • Type inference (tooltips)
  • Go To Definition, Navigation, and Search
  • Comment/uncomment blocks of code

If you’re new to Visual Studio or F#, I hope this is a great way to learn a little more about the VS IDE.  If you’re more experienced, you might still learn a new keyboard shortcut, or discover a previously-unknown feature of VS.

The code on the screen during the video is a little EDSL (Embedded Domain-Specific Language) for a subset of LOGO.  The full code is below; you can just copy it into an F# application project to run it.  It uses WPF for graphics, so you’ll need to add references to the standard WPF assemblies (PresentationCore, PresentationFramework, System.Xaml, System.Xml, UIAutomationTypes, and WindowsBase).  Have fun!

open System
open System.Windows 
open System.Windows.Controls 
open System.Windows.Shapes 
open System.Windows.Media 

[<Measure>] 
type deg
[<Measure>] 
type rad = 1

type Command =
    | Fwd of int
    | Left of int
    | Right of int
    | PenUp
    | PenDown
    | Repeat of int * Command list

let Repeat n cmds = Repeat(n,cmds)  // for syntactic elegance of EDSL

let MillisecondsToSleepBetweenCommands = 30
let WIDTH = 400.0
let HEIGHT = 300.0
let PI = System.Math.PI 
let deg2rad (d:float<deg>) : float<rad> = d * PI / 180.0<deg>

type MyWindow(theDrawing) as this =
    inherit Window(Title="Fun LOGO drawing")
    
    let canvas = new Canvas(Width=WIDTH, Height=HEIGHT)
    let mutable curX = WIDTH / 2.0
    let mutable curY = HEIGHT / 2.0
    let mutable curT = 0.0<deg>
    let mutable isPenDown = true
    let turtle = 
        // a right-pointing triangle centered about the origin
        let points = PointCollection [  Point( -5.0, -10.0)
                                        Point(  5.0,   0.0)
                                        Point( -5.0,  10.0)
                                        Point( -5.0, -10.0)  ]
        points.Freeze()
        let poly = new Polygon(Points = points, Stroke = Brushes.Green)
        canvas.Children.Add poly |> ignore
        poly
    let update() = async {
        Canvas.SetTop(turtle, curY)
        Canvas.SetLeft(turtle, curX)
        turtle.RenderTransform <- new RotateTransform(Angle=float curT)
        do! Async.Sleep MillisecondsToSleepBetweenCommands
        }
    do
        Canvas.SetTop(turtle, curY)
        Canvas.SetTop(turtle, curX)
        this.Content <- canvas
        this.SizeToContent <- SizeToContent.WidthAndHeight 
        this.Loaded.Add (fun _ ->
            async {
                do! Async.Sleep 200
                for cmd in theDrawing do
                    do! this.Execute(cmd)
            } |> Async.StartImmediate 
        )

    /// <summary>
    /// Execute a single LOGO command and update the screen
    /// </summary>
    /// <param name="command">The Command to be executed</param>
    member this.Execute command = async {
        match command with
        | PenUp ->
            isPenDown <- false
        | PenDown ->
            isPenDown <- true
        | Fwd n -> 
            let t = deg2rad curT
            let newX = curX + float n * cos t
            let newY = curY + float n * sin t
            if isPenDown then 
                let line = new Line(X1=curX, X2=newX, Y1=curY, Y2=newY, Stroke = Brushes.Black)
                canvas.Children.Add line |> ignore
            curX <- newX
            curY <- newY
            do! update()
        | Left t ->
            curT <- curT - float t * 1.0<deg>
            do! update()
        | Right t ->
            curT <- curT + float t * 1.0<deg>
            do! update()
        | Repeat(n,cmds) ->
            for _ in 1..n do
                for cmd in cmds do
                    do! this.Execute cmd
        }

let EYE = Repeat 1 [ PenDown; Repeat 8 [ Fwd 20; Right 45 ]; PenUp ]

let DRAWING = [ // go to good start location
                PenUp
                Left 135
                Fwd 80
                Right 135
                // left eye
                EYE
                // move right
                Fwd 80
                // right eye
                EYE
                // go to mouth corner
                Fwd 60
                Right 90
                Fwd 90
                // smile
                PenDown
                Right 45
                Fwd 60
                Right 45
                Fwd 100
                Right 45
                Fwd 60
                // circle around face
                PenUp
                Left 135
                Fwd 80
                Left 90
                Fwd 30
                PenDown
                Repeat 8 [
                    Fwd 100
                    Left 45
                ]
              ]

[<STAThread>]
do
    let app = new Application()
    app.Run(new MyWindow(DRAWING)) |> ignore

Advertisements

2 Responses to “Using VS2010 to edit F# source code (and a little LOGO EDSL)”

  1. zproxy said

    Hey, I seem to be unable to find the source code for LOGODraw. Where is it? :) Thanks!

  2. zproxy said

    Ah, Its the code shown in the blog isn\’t it!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: