using Programming;

A Blog about some of the intrinsics related to programming and how one can get the best out of various languages.

Getting started with programming and getting absolutely nowhere (Part 12)

How do we become experts?

Lesson 11: Why do we compose?

As I've written this series, I've realized I haven't covered one very important aspect of becoming a programmer: how do we become experts? How do we get better?

Programming well is not easy

Any seasoned software developer can tell you that becoming a good programmer is not an easy task, but I'll let you in on a little secret: becoming good at anything requires a lot of practice, and many failures. If you ask any athlete, you'll get the same response. Programming shares this facet.

So with all this said, I want it to be painfully clear: programming takes practice. It takes a lot of practice, refining your skills, honing your talents, and focusing on what's important: solving problems. As a software engineer you are expected to solve problems, in whatever manner you must. Because programming takes practice, I want to continue solving problems with you, and guide you towards how we should think about them.

If you've ever wondered how the 'pros' write complex, structured code, it's actually just a great deal of practice and studying (much like any other activity). In fact, we often write simplistic code at the beginning, and begin reducing it to more complex, but concise code. We're going to explore some examples of that today.

Example one: eliminating lambda's

One of the most common things I do in F# is a lambda. That is, an anonymous function of the form fun <parameters> -> <expression>, you'll find that you end up using these a lot because they're easy to express: define the activity you need to do and do it. We'll take the following example and eliminate each lambda.

Initially you might write some code that looks like the following (I purposefully violated a couple aspects of F# here, bear with me we'll fix them):

let rows =
    [parameters.InitialOffset..mainSheet.LastRowNum]
    |> List.map (fun num -> num |> mainSheet.GetRow)
    |> List.map (fun row ->
        match row with
        | null -> None
        | _ -> Some row)
    |> List.filter (fun rowOpt -> rowOpt.IsSome)
    |> List.map (fun x -> x |> Option.get)

Which is clear, tells us exactly what is happening, but can be made shorter and more idiomatic.

The first thing to note is the List.map lambda. If you ever see a lambda of the form fun x -> x |> someFunctions, you should understand that you can completely eliminate the lambda here. We can rewrite fun x -> x |> someThing as someThing, no need for the fun x -> x |>. This also applies if you're writing functions of the form someThing(x), or someThing x. If the lambda has one parameter, and we're using that parameter only for a single call, then we can remove the entire lambda and replace it with the function chain.

|> List.map mainSheet.GetRow

Boom, done. Next, we can eliminate that last List.filter and List.map with a single List.choose:

|> List.choose (fun x -> x)

Which now introduces an interesting idea: how do we reduce fun x -> x to a single function call?

Well, F# has a handy, built-in function called the 'identity function', or id for short. This function is essentially the same as our lambda, so we can replace fun x -> x with id:

|> List.choose id

Next, we should realize that List.choose can work in place of our second List.map, so we'll replace that:

let rows =
    [parameters.InitialOffset..mainSheet.LastRowNum]
    |> List.map mainSheet.GetRow
    |> List.choose (fun row ->
        match row with
        | null -> None
        | _ -> Some row)

And now we get to another interesting function that requires some framework knowledge: we can actually replace that entire List.choose lambda with a single function: Option.ofObj. This function takes any 'object' type and returns an Option: None if the object was null, and Some object if it was not.

let rows =
    [parameters.InitialOffset..mainSheet.LastRowNum]
    |> List.map mainSheet.GetRow
    |> List.choose Option.ofObj

There is also an Option.ofNullable, which works on nullable value-types (like a nullable 'int').

Example two: identifying functionality that can be abstracted

In one of my work projects, I have the following function, which should definitely be reduced:

let compare (m1 : SpecPerson) (m2 : SpecPerson) =
    let result = 
        m1.FirstName = m2.FirstName
        && m1.LastName = m2.LastName
        && m1.State = m2.State
    let result =
        result &&
        match m1.MagicId, m2.MagicId with
        | Some a, Some b -> a = b
        | _ -> true
    let result =
        result &&
        match m1.MiddleName, m2.MiddleName with
        | Some a, Some b -> a = b
        | _ -> true
    let result =
        result &&
        match m1.City, m2.City with
        | Some a, Some b -> a = b
        | _ -> true
    let result =
        result &&
        match m1.Zip, m2.Zip with
        | Some a, Some b -> a = b
        | _ -> true
    let result =
        result &&
        match m1.OtherThing, m2.OtherThing with
        | Some a, Some b -> a = b
        | _ -> true
    result

If it's not painfully obvious here, I'm comparing several values, and in the case of optionals, if not both of the things are Some, then considering them true. We can really abstract that to a higher-order function:

let compare (m1 : SpecPerson) (m2 : SpecPerson) =
    let optionalComparison a b =
        match a, b with
        | Some a, Some b -> a = b
        | _ -> true
    m1.FirstName = m2.FirstName
    && m1.LastName = m2.LastName
    && m1.State = m2.State
    && optionalComparison m1.MagicId m2.MagicId
    && optionalComparison m1.MiddleName m2.MiddleName
    && optionalComparison m1.City m2.City
    && optionalComparison m1.Zip m2.Zip
    && optionalComparison m1.OtherThing m2.OtherThing

Now doesn't that seem nicer? We should always try to identify what's common and pull it up a level, so we can reuse it. This is a really tough thing to be able to do in the beginning, so I don't expect you to get it right away. As you gain experience you'll learn what can be lifted out more effectively, and you'll gather a stronger understanding of what is important to lift out.

Example three: think critically about what you're doing

I recently had the following match in a project I was working on:

match p with
| One OtherSpecific
| Multiple (AnyNumber OtherSpecific)
| Multiple (Two OtherSpecific)
| Multiple (Zero OtherSpecific)
| Multiple (Many OtherSpecific) -> doSpecificThing
| One OtherNonspecific
| Multiple (AnyNumber OtherNonspecific)
| Multiple (Two OtherNonspecific)
| Multiple (Zero OtherNonspecific)
| Multiple (Many OtherNonspecific)  -> doNonspecificThing

Of course, we can really improve this, what terrible dev wro—....oh yeah, me. We should realize that we're doing something that can easily be pushed away:

let getSpecificity q =
    match q with
    | One s
    | Multiple (AnyNumber s)
    | Multiple (Two s)
    | Multiple (Zero s)
    | Multiple (Many s) -> s

match p |> getSpecificity with
| OtherSpecific -> doSpecificThing
| OtherNonspecific -> doNonspecificThing

I'm supposed to be a professional and I let that ugly mess live in a project for quite some time, so if you ever begin to doubt yourself: even the good programmers do it.

You may also notice that this is no shorter than the original version (both are 11 lines, though the second version has a debatable line-break), but interestingly, this version is reusable, if we ever have to getSpecificity elsewhere, we can. This should be incredibly important to you, and you absolutely must consider it: if something is generic, build it to reuse it.

You may not be perfect, but no one is

I don't think I've stated it in this series yet, so here we go: you may not be perfect, but no one is. Programming is a way of thinking, it's an entire mindset. If you stick with it, you'll eventually become so familiar with the entire process that it'll become second nature, you'll begin looking at things more clearly. There will be several "aha" moments — one day you'll be sitting on the porch thinking about something completely unrelated, and then an epiphany will hit, and things become immedately clear. This happens to all of us, and it will most probably happen to you.


Every time I write one of these I reflect on what the previous lessons include, and continually disappoint myself. I really, really expected to do better for you all, and I promise it'll come. If anyone wants a specific topic or 'thing' (where 'thing' can be a feature, concept, problem) covered, please let me know on Twitter. I want you to want to read this, and for that to happen I need to know what you want to see. You can also comment on this post, I read all comments and (unfortunately) delete most as spam, but it's a safe medium to reach out.

Getting started with programming and getting absolutely nowhere (Part 11)

Why do we compose?

Lesson 10: Building some 'fuzzy logic' for our names

If you've been following along in this series (which I recommend that you do, it starts way back here), you'll notice that I've done a lot of a |> (g >> f), and not as much a |> g |> f or f(g(a)), if you're a curious person (which you should be, curiosity is the only way we learn something new), you're probably wondering why. Why do I write things as a |> (g >> f)` rather than the other two options? Well, today's lesson is going to go into that and help us learn what the differences are, so that hopefully things are more clear to you in the future.

First thing first, what is the purpose of these three things?

Before we begin our adventure, I want to refresh our memory back to lesson 1, when I said:

The pipe-right (|>) operator takes the value on the left side, and transforms it to be the last argument of the function on the right side.

So we need to define an even more basic idea first, because pipe-right works on that. So let's do that.

In programming, we often work with something called a function or method, now these terms are sometimes interchangeable, and sometimes not, but we'll define a function first:

A function is a symbol that takes one parameter and returns one value.

So what's a symbol?

In software-engineering, programming, whatever you call it, a "symbol" is a name mapped to a memory location. This is an important concept, because we often thing of symbols to a value (let x = 5) as being the value themselves: they're not. The symbol x is a memory-pointer to a portion of memory that holds the value of 5.

So, think of it this way: if you look in your phone 'contacts' you see a "name", but that name often has a "number" associated with it. When you call or text someone you don't call their name, you call the number. The name is a "symbol" that points to the "number". Hopefully that helps clear it up.

So if a function is a symbol, what does it point to?

That depends, and I'm not nearly educated enough to go into full details on that, but I'll give you the "skinny":

  • When you declare a function let f = (+) 5, you declare a "symbol" (f in this case) that maps to a set of instructions ((+) 5 in this case).
  • When you call "f" (such as f(3)), you are actually asking the software to load the instructions, and then execute them with the value "3" being passed as parameter. Of course, it's not obvious here because I used composition, so let's redefine f: let f x = x + 5. Now is it clear? We have a memory location that is a set of instructions (there are three, we'll get into that shortly) that performs x + 5.
  • When you pass x to f, you are passing it via a "stack", which is an internal memory component that can be read to and written to, but only the top value. This is another important concept. We only ever see the "top" value of the stack, or the last one to be pushed in.

So, here's a more clear example:

  • let x = 5: declares a symbol "x" that ponts to an address of value 5;
  • let f x = x + 5: declares a symbol "f" that points to a function that expects a single parameter bound to symbol x (a different x) then exectues the instruction x + 5 (plus at least two others, again I'll get to that later);
  • let y = f x: declares a symbol y that is the symbol x passed as the first parameter to the function of symbol f, then places the result of that into an address bound to symbol y;

Alright, so does that make sense? Now we understand that f is just a symbol, that points to a memory location with some instructions. So this introduces composition, which is the idea that we can build a function out of smaller parts. Let's define g: let g x = x * 2.

So the symbol g points to a memory location that says "load and execute the three instructions", but this means we can build the composite function g of f: let gf = g >> f. Think of the >> operator as being "and then", we say "do g, and then do f with the result." We can also let fg = f >> g, which is "do f, then do g". The interesting thing is that the symbol gf or fg is just a symbol holding the two functions, and saying "when you get done with the first, give that result to the second, then give me the result."

So now let's go through our example:

let x = 5 // Bind `5` to the symbol `x`, `x` is a value of `int`
let f = (+) 5 // Bind `+ 5` to the symbol `f`, `f` is a function of `int -> int`
let g = (*) 2 // Bind `* 2` to the symbol `g`, `g` is a function of `int -> int`
let gf = g >> f // Bind `g and then f` to the symbol `gf`, `gf` is a function of `int -> int`
let y = x |> gf // Bind the result of `gf x` to the symbol `y`, `y` is a value of `int`

Now at the moment we define y, gf gets executed with the value x, which in tern means g gets executed with x, then f gets executed with g(x). Interestingly, we can model this entire operation more clearly:

let gf x =
    let x_g = g x
    f x_g

Now the problem here is that it takes more time and consideration to realize what happened (after you get used to composition, obviously): we bound an intermediate symbol to the result of g, then returned the result of f with that intermediate symbol. Interestingly gf will have the same int -> int signature at the root level, but it is now defined as let gf (x : int) : int =, rather than let gf : int -> int =, which is a subtle but important difference: gf now directly relies upon the top value of the stack rather than indirectly.

Now I'm noting this because I want to show you the pipe-right option of gf: let gf x = x |> g |> f, which is equivalent to let gf x = f (g x). So we now have three options for writing gf (all being an equivalent result):

let gf x = f (g x) // Write them as parameterized calls
let gf x = x |> g |> f // Write them as piped calls
let gf = g >> f // Write them as a composition

I would choose the last result each and every time and I want you to understand why: when we see let gf = g >> f, we should immediately think to ourselves that gf is a single step, composed of sub-steps g and then f. The important part there is that gf is a single step, it's a single operation, it stands for one thing to do, whereas x |> g |> f stands for multiple things to do. It may not imply it directly, but it indirectly says "take x, do g with it, then do f with that result", whereas g >> f says "do g and then do f immediately." Yes, all three mean the same thing, and yes, all three result in the same value, but it's important for us to write our code readably, we want people to understand it. When I see f (g x) I think "do f, then do g with x, and give that to the f being done." It's much harder to see the immediate idea that f is just the next step in the pipeline, especially once you get to curried or "multi-parameter" functions.

We can also note that let gf = g >> f is shorter than the other two results, in number of characters and time to type. (I'm faster at > than ( or ), for example, and I'd bet you probably are too.)

Bottom line, pick the clearest option

I want to boil this entire discussion down to one idea: write the code that's most obvious. Write the code that's most clear. Write the code that's most meaningful. We've had a trope in the software engineering world for a long time:

Write your code as if the person that has to maintain it is a violent sociopath who knows where you live.

Don't write "clever" things (unless theres a very good reason to), write things that are direct, obvious and say what they mean.

What are the three instructions I talked about earlier?

Right, so I want to clarify this one, when I said we define let f x = x + 5 being three instructions, what do I mean by that?

Well, in the software engineering world we don't get anything for free (except coffee sometimes, but only if we have a good employer). We pay for everything. When we define let f x = x + 5 we have to do at least three things here:

  1. Load the top value in the stack to x;
  2. Perform the (+) operation with x and 5;
  3. Return the result;

We have to do all three, and even if we write-off + as two function calls (because it is, it takes two arguments so it's two calls), we have to do at least those three things. We have to load the top value on the stack, we have to perform our + 5 (we'll call that one instruction), and we have to return that value.


I've slowed down on these posts for the moment, largely because a lot of my free time has been lost, but I'm going to continue to do at least one a week, and when I get more time I'll be doing them more than that. I have a few different projects I'm working on that will all be described here in time, so we'll be going into some pretty advanced topics, so it would be prudent to try to study a few of these things in your free time, as we have a lot to cover yet.

Getting started with programming and getting absolutely nowhere (Part 10)

Building some 'fuzzy logic' for our names

Lesson 9: Knowing the terminology is important

If you recall, in lesson 7 I mentioned the following:

We'll then (at a later date) explore how we can modify it to account for multi-part last names, such as LA ROUSE, or MAC GREGOR. This is a lot harder than it looks, and we'll only worry about that for Sheet 2, because in Sheet 1 it's always separated out.

Today, we're going to explore this part of our topic - we'll build some 'fuzzy logic' that doesn't seem fuzzy, but happens to be. Of course, first we need to define 'fuzzy logic', so let's do that.

What is 'fuzzy logic'?

Fuzzy logic is used fairly often in programming, it's essentially building a set of rules that sacrifice one of the following to make up for the other two: predictability, accuracy, and speed. Ours will sacrifice accuracy for speed and predictability. We're going to build a function that is mostly correct, but sometimes wrong, to allow us to solve the 95% scenario.

We need some "rules" for our fuzzy logic, so let's define them:

  • If a word is <= 3 characters, it's part of a "compound word";
    • A compound word should be grouped with the next word if possible;
  • If a word is a single character followed by a single period, in any quantity, it's an "initial";

In [lesson 8], we built splitNames:

let splitNames (name : string) =
    match ' ' |> name.Split with
    | [|first; last|] -> (Some first, None, Some last)
    | [|first; middle; last|] -> (Some first, Some middle, Some last)
    | _ -> (None, None, None)

This isn't fuzzy logic so much as bad logic: we just assume that two parts = first, last name, and three parts = first, middle, last name. We make absolutely no guarantee that there's even an apporpriate value there, for the name of John Mac Gregor, we get (Some John, Some Mac, Some Gregor). That's not right at all, for Rhonda La Rouse, we get (Some Rhonda, Some La, Some Rouse), again wrong.

So let's define portions of our 'fuzzy logic':

let isInitial : char array -> bool = (function | [|_; '.'|] -> true | _ -> false)

Good start, we test a char array for two elements of anything, '.'. We can test this easily: "a." |> Seq.toArray |> isInitial, which passes.

Now we need a function, isOnlyInitials which tells us if a string only consists of initials, i.e. D.W. should be true:

let isOnlyInitials : string -> bool =
    Seq.toArray
    >> Array.mapi (fun i x -> (x, i))
    >> Array.groupBy (fun (x, i) -> i / 2)
    >> Array.map snd
    >> Array.map (Array.map fst)
    >> Array.forall isInitial

This is an interesting function, because we use mapi to give us the index and element, then groupBy to put them into pairs, then map to only get the second element (x, i), then map (map fst) to give us just the first element from each sub-array. We're left with just forall isInitial, which is equivalent to Array.filter isInitial |> Array.length = 0. Simple, right?

Let's appy this to our existing function

So how do we apply this? We need to modify splitNames to account for the initial, and for the compound name. To do so, we'll get rid of the match, because we're now just going to work our fuzzy logic. First we need to get the parts:

let nameParts = ' ' |> name.Split

That's a good start, and it gives us an array of string objects representing each part. Previously this was all we needed, but now we need to put them into groupings based on our new rules.

Now we need to "fold" over our names, and collect them into an array of names that are based on our rules. For this we'll build a folder that takes a string list and then a string and returns a string list, with the first element being the last element tested.

The basic idea here is to match acc with prev::rem, and if prev is <= 3 characters, and it's not only initials, then our new prev should be prev part.

nameParts
|> Array.fold (fun acc pt ->
        match acc with
        | prev::rem
            when prev |> Seq.length <= 3
                && prev |> (isOnlyInitials >> not) ->
            (sprintf "%s %s" prev pt)::rem
        | _ -> pt::acc
    ) []

Make it work for Ron, darnit!

Pretty simple, right? So if we test it with a basic data-set: ["John Mac Gregor"; "Rhonda La Rouse"; "John C. Mac Gregor"; "Rhonda A. La Rouse"; "La Ronda Doe"] |> List.map splitNames;;, we can see that it returns what we expected. Now, we lose one particular case I ran into: "Do Ray Doe", which turns into (Some "Do Ray", None, Some "Doe"), when it should have been (Some "Do", Some "Ray", Some "Doe"). We also lost support for Ron Doe, which returns all None because Ron is paired with Doe. To fix this we'll alter our when guard clause:

let splitNames (name : string) =
    let isInitial : char array -> bool = (function | [|_; '.'|] -> true | _ -> false)
    let isOnlyInitials : string -> bool =
        Seq.toArray
        >> Array.mapi (fun i x -> (x, i))
        >> Array.groupBy (fun (x, i) -> i / 2)
        >> Array.map snd
        >> Array.map (Array.map fst)
        >> Array.forall isInitial
    let nameParts = ' ' |> name.Split
    let nameParts =
        nameParts
        |> Array.fold (fun acc pt ->
                match acc with
                | prev::rem
                    when prev |> Seq.length <= 3
                        && prev |> (isOnlyInitials >> not)
                        && rem |> List.length >= 1 ->
                    (sprintf "%s %s" prev pt)::rem
                | prev::rem
                    when prev |> Seq.length <= 2
                        && prev |> (isOnlyInitials >> not) ->
                    (sprintf "%s %s" prev pt)::rem
                | _ -> pt::acc
            ) []
        |> Array.ofList
        |> Array.rev
    match nameParts with
    | [|first; middle; last|] -> (Some first, Some middle, Some last)
    | [|first; last|] -> (Some first, None, Some last)
    | _ -> (None, None, None)

We also added a second prev::rem case, the first matches if there's already more than one other word with a length of <= 3 (so Ron Doe is fixed), the second matches any if the first word is <= 2 characters (working for La Ronda, but not properly for Bo David). Now we could add a filter for Bo to not match on the <= 2 guard clause, but that adds a maintainability issue. Instead, we just document that it's 99% accurate, and what cases we know won't work properly.


Today's lesson is somewhat short, but introduces a very complex topic. I recommend that you make sure you fully understand what is happening, as it's important to know. Also, if anyone has a better idea on the isOnlyInitials function, I'd be very interested in hearing about it. The grouping by index / 2 works, but I'm sure there's a better way to do it.

Running F# code in PowerShell

Impromptu Blog Post: Loading F# Into PowerShell

My friend Chris asked on Twitter, if it was possible to load an F# module to PowerShell. For anyone who's heavily familiar with PowerShell, we know that it's very possible to load a .NET assembly to PowerShell, and run methods and operations in it.

To run an F# module in PowerShell, we simply need to add an extra step: load FSharp.Core.dll before we try to call our method.

To test this, I built a quick F# project: PowerShell Test Library, and added the following code:

namespace PowerShell_Test_Library

type TestClass() = 
    member this.run () = printfn "This is an F# function"
    static member runStatic () = printfn "This is a static F# function"

Basic, right? This is just demonstrative, but let's take a peek and see how we can load it. The first step to loading a .NET library into PowerShell is to call System.Reflection.Assembly.LoadFile, which is done as follows:

[System.Reflection.Assembly]::LoadFile("C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug\PowerShell_Test_Library.dll")

Yes, you need the full path when using it like this. Next, we load FSharp.Core.dll:

[System.Reflection.Assembly]::LoadFile("C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug\FSharp.Core.dll")

We can call our methods as follows:

(New-Object PowerShell_Test_Library.TestClass).run()
[PowerShell_Test_Library.TestClass]::runStatic()

So, altogether, our PowerShell is:

[System.Reflection.Assembly]::LoadFile("C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug\PowerShell_Test_Library.dll")
[System.Reflection.Assembly]::LoadFile("C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug\FSharp.Core.dll")
(New-Object PowerShell_Test_Library.TestClass).run()
[PowerShell_Test_Library.TestClass]::runStatic()

If we run this, we get the following:

PS C:\Users\ebrown\Desktop> [System.Reflection.Assembly]::LoadFile("C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug\PowerShell_Test_Library.dll")

GAC    Version        Location
---    -------        --------
False  v4.0.30319     C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin...


PS C:\Users\ebrown\Desktop> [System.Reflection.Assembly]::LoadFile("C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug\FSharp.Core.dll")

GAC    Version        Location
---    -------        --------
False  v4.0.30319     C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin...


PS C:\Users\ebrown\Desktop> (New-Object PowerShell_Test_Library.TestClass).run()
This is an F# function
PS C:\Users\ebrown\Desktop> [PowerShell_Test_Library.TestClass]::runStatic()
This is a static F# function
PS C:\Users\ebrown\Desktop>

And it's that easy.

For anyone familiar with PowerShell, if your ExecutionPolicy does not permit running a script, you can use the following function to run it instead:

function Run-Script ([string]$script)
{
    $policy = Get-ExecutionPolicy
    Set-ExecutionPolicy -Force -Scope CurrentUser -ExecutionPolicy Bypass
    & ".\$script"
    Set-ExecutionPolicy -Force -Scope CurrentUser -ExecutionPolicy $policy
}

Drop that in your PowerShell console, and then call Run-Script ScriptFile.ps1, which for me is Run-Script Script.ps1. This will set and restore your ExecutionPolicy to run the script:

PS C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug> function Run-Script ([string]$script)
>> {
>> $policy = Get-ExecutionPolicy
>> Set-ExecutionPolicy -Force -Scope CurrentUser -ExecutionPolicy Bypass
>> & ".\$script"
>> Set-ExecutionPolicy -Force -Scope CurrentUser -ExecutionPolicy $policy
>> }
PS C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug> Run-Script Script.ps1

GAC    Version        Location
---    -------        --------
False  v4.0.30319     C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin...
False  v4.0.30319     C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin...
This is an F# function
This is a static F# function


PS C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug>

And this concludes our main lesson for today. :)


Make it a little better

Of course, we can make this just a little better.

First, we don't want to have to manually specify the path. So we'll get the current path:

$path = (Get-Item -Path "." -Verbose).FullName

Second, we don't really need to see the GAC lines from the libraries being added, we don't really care about them. The easiest way to do this is to redirect the output to $null, via > $null:

[System.Reflection.Assembly]::LoadFile("$path\PowerShell_Test_Library.dll") > $null
[System.Reflection.Assembly]::LoadFile("$path\FSharp.Core.dll") > $null

This will make our new script less verbose.

PS C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug> Run-Script Script.ps1
This is an F# function
This is a static F# function
PS C:\Users\ebrown\Documents\Visual Studio 2017\Projects\FSharp Tests\PowerShell Test Library\bin\Debug>

It also builds a reusable framework for future scripts: we can replace the first LoadFile with our apporpriate file, so we may actually want to abstract that:

function Init-Script ($dll)
{
    $path = (Get-Item -Path "." -Verbose).FullName
    [System.Reflection.Assembly]::LoadFile("$path\FSharp.Core.dll")
    [System.Reflection.Assembly]::LoadFile("$path\$dll.dll")
}

Then the actual script code is:

Init-Script "PowerShell_Test_Library" > $null
(New-Object PowerShell_Test_Library.TestClass).run()
[PowerShell_Test_Library.TestClass]::runStatic()

And life is much better.

Getting started with programming and getting absolutely nowhere (Part 9)

Knowing the terminology is important

Lesson 8: Let's Normalize Our Data!

Recently I was talking with a colleague of mine, and we were discussing certain syntax differences between two of the major .NET languages: C#, and VB.NET. (Sorry, he's not a fan of F# so there's no love for it there.) One of the issues we came across was the following syntax:

VB.NET:

Public Property Items As List(Of String)

C#:

public List<string> Items { get; set; }

In particular, we were concerned with the (Of String) and <string> bits - if you remember back to lesson 4, I talked about the <'a> bit of let flatten<'a> : 'a array array -> 'a array = Array.collect id, which was an F# generic-type parameter, or a placeholder for a type. It means you can call essentially replace 'a with any type (in this case you actually can, because there are no type constraints) and the function should still work. The (Of String) and <string> bits of the examples above are the same principle: each one is a type substituted for a generic type parameter, that is, the "generic type" of List is now a string. In VB.NET this is accomplished by the verbose Of T, in C# and F# it's accomplished by <T>, which hilariously, as my friend Chris points out on Twitter, is pronounced as Of T by pretty much any seasoned developer. (This should make things a little easier to understand: a 'a array is just an array of 'a.)

But this brought up an even larger issue - it's important for people to understand the terminology of the system they work in. I can't stress this enough, and if you remember back to that lesson, I even had the following to say:

The <'a> is an F# generic type-parameter. Feel free to look those up to learn more.

I really hope you looked it up, because it's important to understand what it means. Often times in any field we get into the habit of using field-specific terms, in this case "generic type parameter", but other terms may be things like "monad" (often found in Haskell documentation), "access(ibility) modifier" (public/protected/internal/private, etc.), or even something as simple as a "mouse". (When talking to a computer group, "mouse" often refers to the physical device used to move a cursor on a GUI, but if you are speaking to a verternarian or someone from animal-control, I assure you it's not as clear-cut.)

The Electronics Example

In fact, recently I was looking for advice on a specific motor to use with a PLC, and I mentioned to a person that I needed a "DC brushless motor" - now if you don't know how "DC" or "brushless" apply to "motor", that sentence can be confusing, misleading, or altogether unable to be understood, but in the context it meant "a device that converts direct-current electric energy into rotary motion, without the use of any brushes." Again, not too confusing, but if you don't understand or incorrectly understand the term, it can be very difficult to rectify the situation. (The particular person I was talking to kept telling me "you can use a car starter" - this is problematic because a car starter is usually a brushed DC motor - I specifically needed brushless.)

So, I want to take a moment today to, instead of writing code, go over some of the common (and hopefully some of the less common) terms you might run into in programming. Some of which I'll describe, and some of which I'll tell you the term, but expect you to research it.

Some Terms

The first set of terms is pretty basic, these are usually basic types in a programming language, or can be trivially represented.

  • Method: a section of programming code with an identifier and optionally parameters that may be called by other code, and may or may not return a value;
  • Function: a method that always returns a value;
  • Subroutine: a method that never returns a value, or returns a void-type;
  • Boolean or Bool: a value that has two states: true or false;
  • String: a sequence of characters that represent a section of text;
  • Integer: a whole number (that is, a number with no fractional portions);
  • Single-Precision Floating-point Value, Single or Float: a number with a fractional part, often represented as a 32-bit value (Do note that some languages treat a float as a double, research the language ahead of time to make sure you understand which is the case);
  • Double-Precision Floating-point Value or Double: a number with a fractional part, often represented as a 64-bit value;
  • Char: a single character, often represented as an 8-bit, 16-bit or 32-bit value (Different languages and systems use different endian-ness, bit-sizes and encodings for char, your specific details may vary);
  • Byte: an 8-bit value either signed or unsigned depending on language;
  • Endian-ness: the order in which bits and bytes appear, this may be most-significant value first, or least-significant value first (see big-endian and little-endian);
  • Bit: see Boolean, this is a single value that is represented by either a 0 or 1;
  • Signed/Unsigned: whether a number has the ability to represent values below 0 (signed) or may only represent values above 0 (unsigned);
  • Short or Int16: typically a 16-bit integer, either signed or unsigned;
  • Long or Int64: typically a 64-bit integer, either signed or unsigned;
  • Word: this is not a "word" in the sense of a sentence, but is typically an alias for a "short" or "Int16" - it is two bytes, always (I separated this and the next two from the number types closest to them because they have a literal translation: they are always the specified number of bytes - often times platforms and languages will indicate that a "numeric" type is actually one of these, such as "int" typically being a "DWord");
  • DWord or Double Word: two words (4 bytes);
  • QWord or Quad Word: four words (8 bytes);

Regarding numbers: often times languages provide number types in a pair, such as sbyte and byte for "signed byte" and "unsigned byte", or short and ushort for "signed short" and "unsigned short", respectively. This often creates confusion between languages, and to make matters worse C and C++ don't always use the same bit-length for each data-type. (On some platforms int in C may be 8, 16, or 32 bits.) The terminology I'm using is referring to the .NET types, for the most part, and it also refers in general on a broader level. (An Int16 is the same 16-bits no matter what, and most people in the software development industry understand short is an alias for Int16.)

Some more types and type-modifiers:

  • Class: often refers to a reference-type that is a collection of related fields, properties, methods and events;
  • Struct: often refers to a value-type that is a collection of related fields, properties, methods and events;
  • Reference-Type: a type that is, by default, treated as a reference rather than an actual value, this is similar but not the same as a pointer - the value of the reference type is a memory-address that points to the actual values;
  • Value-Type: a type that is, by default, treated as an actual value, that is, a single continuous grouping of memory that represents a single result (things like "numbers" - one would never expect int value = 0 to be a pointer to a memory location holding an "object" with the value 0 - it's just expected that value is now the literal 0);
  • Interface, Protocol or Contract: usually refers to a collection of properties, methods and events which a class or struct intends to fully implement;
  • List: may either refer to a "linked-list" or a "non-linked list" of values, usually of the same type - the list often has a "count" of the number of items contained, and often methods like "add", "remove" and "contains" to indicate if an element is in the list;
  • Sequence or Enumerable: any sequence of values, usually of the same type, that are in order but may not always be known ahead-of-time - these are often "lazily" processed, in that only the current element of the sequence is known, the next element may or may not actually have been found already - usually a List can be treated like a Sequence, as a List is inherently a sequence of values;
  • Array: a set of values, usually of the same type, that are directly indexable and statically referenced in memory - a string, for example, can be seen as an "array of characters" - these may or may not expose a "count";
  • Access(ibility) Modifier: a keyword that indicates what "access level" a class, interface, enumeration, property, field, event or method allows;
  • Base Class: in the concept of OOP and inheritance, the class that is the next level up the heirarchy;
  • Abstract Class: a class that is not concrete, but may provide some portions of an implementation of - may only be inherited by other classes;

Paradigms and paradigm-related terms:

  • OOP or Object-Oriented Programming: designing programs around the model of data-flow being done through inheritance, and polymorphism (often statement-based);
  • Functional Programming: designing programs around the model of data-flow being done through functions and functional composition, rather than classes or inheritence (often expression-based);
  • Expression: a series of instructions that evaluate to a value (such as 1+1);
  • Statement: typically an "expression" that doesn't return a result (a call to a method, for example, with a void return type);
  • Polymorphism - look this one up on your own, far too long to describe properly here;
  • Instruction: typically refers to a basic operation that may be performed on a lower-level than usual programming;

Some basic algorithms you should research:

  • Binary Search
  • Binary Search Tree
  • Heap Sort
  • Quicksort
  • Insertion Sort

I'll probably be updating this list as time goes on, but at the very least these are some terms you should get mostly acquainted with.


Todays post is (obviously) more about the higher-level aspects of programming, and less about doing something. I should have convered this information previously, but I didn't. This will become a reference document for future ideas as well (anything I explain here I'll not explain in the future), so keep updated on it. As we've progressed quickly, we'll continue to do so. I'm largely out of content for this series, we'll do a few updates to our existing program to make it slightly more effective and easier to follow, but I hope to have a new adventure worked out by Monday.