{ "metadata": { "language": "fsharp", "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "

Introduction to F#

" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "This will be an overview of basic F# syntax. \n", "\n", "To learn F# you can start by doing:\n", "\n", "* the introduction lessons at http://www.tryfsharp.org\n", "\n", "Then do some of the following:\n", "\n", "* Project Euler problems http://projecteuler.net \n", "* Learn by testing https://github.com/ChrisMarinos/FSharpKoans\n", "\n", "Other resources:\n", "\n", "* F# reference on MSDN http://msdn.microsoft.com/en-us/library/dd233154.aspx" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Comments" ] }, { "cell_type": "code", "collapsed": false, "input": [ "// this is a comment\n", "(* this is also a comment *)\n", "(* this is\n", " a\n", " multiple line\n", " comment *)" ], "language": "python", "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "###Definitions and Type Inference\n", "\n", "Definitions are made using the ```let``` keyword. F# will infer the type based on the values." ] }, { "cell_type": "code", "collapsed": false, "input": [ "let a = 4\n", "let b = 1.5\n", "let c = \"hello\"\n", "\n", "a,b,c" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 17, "text": [ "val it : int * float * string = (4, 1.5, \"hello\")" ] } ], "prompt_number": 17 }, { "cell_type": "markdown", "metadata": {}, "source": [ "###Math Operators\n", "\n", "There are math keywords build into F#.\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "// exponential power\n", "exp(1.0)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 26, "text": [ "val it : float = 2.718281828" ] } ], "prompt_number": 26 }, { "cell_type": "code", "collapsed": false, "input": [ "// raise to a power for floats\n", "3.0 ** 2.0" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 27, "text": [ "val it : float = 9.0" ] } ], "prompt_number": 27 }, { "cell_type": "code", "collapsed": false, "input": [ "// raise to a power for integers\n", "pown 3 2" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 36, "text": [ "val it : int = 9" ] } ], "prompt_number": 36 }, { "cell_type": "code", "collapsed": false, "input": [ "// modulus\n", "8%3" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 38, "text": [ "val it : int = 2" ] } ], "prompt_number": 38 }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "###Lists\n", "\n", "Lists are defined by brackets [ ]. Also common in F# are arrays [| |] and sequences seq { }. \n", "\n", "To define a sequence of numbers you can use ```start .. end``` or if the increment is other than one use ```start .. increment .. end```." ] }, { "cell_type": "code", "collapsed": false, "input": [ "[1..10]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 2, "text": [ "val it : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]" ] } ], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "[10.0 .. -0.1 .. 1.0]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 2, "text": [ "val it : float list =\r\n", " [10.0; 9.9; 9.8; 9.7; 9.6; 9.5; 9.4; 9.3; 9.2; 9.1; 9.0; 8.9; 8.8; 8.7; 8.6;\r\n", " 8.5; 8.4; 8.3; 8.2; 8.1; 8.0; 7.9; 7.8; 7.7; 7.6; 7.5; 7.4; 7.3; 7.2; 7.1;\r\n", " 7.0; 6.9; 6.8; 6.7; 6.6; 6.5; 6.4; 6.3; 6.2; 6.1; 6.0; 5.9; 5.8; 5.7; 5.6;\r\n", " 5.5; 5.4; 5.3; 5.2; 5.1; 5.0; 4.9; 4.8; 4.7; 4.6; 4.5; 4.4; 4.3; 4.2; 4.1;\r\n", " 4.0; 3.9; 3.8; 3.7; 3.6; 3.5; 3.4; 3.3; 3.2; 3.1; 3.0; 2.9; 2.8; 2.7; 2.6;\r\n", " 2.5; 2.4; 2.3; 2.2; 2.1; 2.0; 1.9; 1.8; 1.7; 1.6; 1.5; 1.4; 1.3; 1.2; 1.1;\r\n", " 1.0]" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "###Functions\n", "\n", "To create a named function the format is: \n", "\n", "```let``` *function_name* *arguments* = *function_body*" ] }, { "cell_type": "code", "collapsed": false, "input": [ "let f x = x + 1\n", "\n", "f 4" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 15, "text": [ "val it : int = 5" ] } ], "prompt_number": 15 }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "###Pipeline\n", "\n", "The pipeline operator ```|>``` is used to use the value on the left side of the operator as the input to the function on the right side of the operator. It is used the chain multiple steps together." ] }, { "cell_type": "code", "collapsed": false, "input": [ "let addOne x = x + 1\n", "let timesTwo x = x * 2\n", "\n", "3 |> addOne |> timesTwo" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 14, "text": [ "val it : int = 8" ] } ], "prompt_number": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ "###Anonymous Functions\n", "\n", "Anonymous functions allow for the creation of \"throw away\" or \"helper\" functions. \n", "\n", "The have the syntax of : \n", "```fun``` *arguments* -> *function_body*" ] }, { "cell_type": "code", "collapsed": false, "input": [ "4 |> fun x -> x+1" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 16, "text": [ "val it : int = 5" ] } ], "prompt_number": 16 }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### FSharp Collections\n", "\n", "http://msdn.microsoft.com/en-us/library/ee353413.aspx\n", "\n", "The F# collection modules have many useful methods that you will need to get familiar with. (List, Array, Seq, Array2D, Set, etc.) \n", "\n", "The following is just a sample of the methods available." ] }, { "cell_type": "code", "collapsed": false, "input": [ "// filter - filters any values that the condition is true\n", "[1 .. 10] |> List.filter (fun n -> n%2=0)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 22, "text": [ "val it : int list = [2; 4; 6; 8; 10]" ] } ], "prompt_number": 22 }, { "cell_type": "code", "collapsed": false, "input": [ "// map - maps a function to each element\n", "[1 .. 5] |> List.map (fun n -> n*n)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 33, "text": [ "val it : int list = [1; 4; 9; 16; 25]" ] } ], "prompt_number": 33 }, { "cell_type": "code", "collapsed": false, "input": [ "// sum - sums the collection, elements must have an add method\n", "[1 .. 5] |> List.sum" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 34, "text": [ "val it : int = 15" ] } ], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": [ "// sumBy - applies a function to each member before summing\n", "[1 .. 5] |> List.sumBy (fun n -> n*n)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 35, "text": [ "val it : int = 55" ] } ], "prompt_number": 35 }, { "cell_type": "code", "collapsed": false, "input": [ "// Seq.unfold - returns a sequence generated by a function\n", "Seq.unfold (fun (a,b) -> Some(a,(b,b+a))) (1,2)\n", "|> Seq.take 5 // take first 5 items in sequence\n", "|> Seq.toList // convert to a list" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 43, "text": [ "val it : int list = [1; 2; 3; 5; 8]" ] } ], "prompt_number": 43 }, { "cell_type": "code", "collapsed": false, "input": [ "// infinite sequence of square integers\n", "Seq.initInfinite (fun i -> i*i)\n", "|> Seq.takeWhile (fun n -> n<100) // take all less than 100\n", "|> Seq.sum // sum" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 7, "text": [ "val it : int = 285" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "###Seq.unfold\n", "\n", "``Seq.unfold`` is not as common as ``map`` or ``sum`` methods, but wanted to give a quick example. It does come up fairly regularly in Project Euler problems so a general understanding can help. When you have a numeric series that is dependent on prior terms ``Seq.unfold`` can be helpful. If prior terms are not needed the simplicity of ``Seq.initInfinite`` is probably perfered." ] }, { "cell_type": "code", "collapsed": false, "input": [ "// short version of Fibonacci expansion\n", "\n", "Seq.unfold (fun (a,b) -> Some (a,(b,a+b))) (1,1)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 11, "text": [ "val it : seq = seq [1; 1; 2; 3; ...]" ] } ], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "// longer version\n", "\n", "let nextFib (a,b) =\n", " let result = a\n", " let nextArgs = (b,a+b)\n", " Some (result, nextArgs)\n", " \n", "// Seq.unfold folder initialState\n", "// folder is a function of (state -> (result, nextState) option )\n", "// as long as 'Some' is returned the sequence of results is created by\n", "// passing subsequent states into the folder function\n", " \n", "Seq.unfold nextFib (1,1)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 14, "text": [ "val it : seq" ] } ], "prompt_number": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ "###Match\n", "\n", "The ```match``` keyword uses pattern matching and can be thought of a case or switch statement (only more powerful)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "let isEven n =\n", " match n with\n", " |x when x%2=0 -> true\n", " |_ -> false\n", " \n", "isEven 5" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ "val it : bool = false" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Recursion\n", "\n", "The ```rec``` keyword is used to indicate that a function can be called recursively." ] }, { "cell_type": "code", "collapsed": false, "input": [ "let rec factorial_v1 n = \n", " match n with\n", " |0|1 -> 1I\n", " |n -> bigint n * factorial_v1(n-1)\n", " \n", "List.init 5 factorial_v1" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 20, "text": [ "val it : Numerics.BigInteger list = [1; 1; 2; 6; 24]" ] } ], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "// tail recursive version (generally preferred versus prior version)\n", "let factorial_v2 n =\n", " let rec loop x acc =\n", " match x with\n", " |0|1 -> acc * 1I\n", " |n -> loop (x-1) (bigint n*acc)\n", " loop n 1I\n", " \n", "List.init 5 factorial_v2" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 1, "text": [ "val it : Numerics.BigInteger list = [1; 1; 2; 6; 24]" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### if ... then ... [elif] ... [else]\n", "\n", "While not as powerful as the ``match`` keyword, ``if`` ... ``then`` can be simplier to implify." ] }, { "cell_type": "code", "collapsed": false, "input": [ "let isEven n =\n", " if n%2 = 0 then\n", " true\n", " else\n", " false\n", " \n", "isEven 100" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ "val it : bool = true" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "###for ... in ... do\n", "\n", "A ``for ... in ... do`` loop can be used within a sequence espression to create sequences/lists/arrays on the fly. If there is no ``if`` condition on a ``yield`` then ``->`` can be used as a replacement of ``do yield``." ] }, { "cell_type": "code", "collapsed": false, "input": [ "[ for i in 1..10 -> i*i ]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 4, "text": [ "val it : int list = [1; 4; 9; 16; 25; 36; 49; 64; 81; 100]" ] } ], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "[ for i = 1 to 10 do yield i*i ]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 5, "text": [ "val it : int list = [1; 4; 9; 16; 25; 36; 49; 64; 81; 100]" ] } ], "prompt_number": 5 } ], "metadata": {} } ] }