Skip to content

Conversation

@cartermp
Copy link
Contributor

I've made quite a few changes to the Tutorial project to align it a bit more with the Tour of F# document. That means a few things:

  • Many more links to documentation for modules which demonstrate language features
  • Some more additions to call out more language features within a particular area
  • Some more module-level organization
  • More comments in places to explain things
  • Minor changes, like adding line breaks to |> pipelines and changing from %A to a more concrete format type when possible

When this is merged (pending changes), I'll be updating the Tour document so that the backing code samples pull from this same source file. I'll probably be modifying a bit of the text, but there shouldn't be too much to change in that document.

I may also push another change which endeavors to add more printfn statements.

cc @dsyme



/// First some basics on integers and numbers
/// Modules are the primary way to organize functions and values in F#. This module contains some
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we explain the difference between // comments and triple-slash comments? It looks like a mix has been used in this document which could be confusing as to what the 'defacto' comment style is, and when/where each type should be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Called out the different comment types up top.

Copy link
Contributor

@saul saul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a really great addition to ease beginners into F#, especially if they're from an imperative background 👍

printfn "The result of squaring the integer 4573 and adding 3 is %d" result1

/// When needed, annotate the type of a parameter name using '(argument:type)'
/// When needed, annotate the type of a parameter name using '(argument:type)'. Parenthesis are required.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be using the plural of parenthesis (parentheses).


/// Strings can also use @ to create a verbatim string literal
let string3 = @"c:\Program Files\"
/// Strings can also use @ to create a verbatim string literal.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe explain that verbatim strings will ignore escape sequences such as \n, \t etc. It may also be useful to demonstrate the logical equivalent: "C:\Program Files\"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed.

printfn "%s" (showPlayingCard card)

// Single-case DUs are often used for domain modeling. This can buy you extra type safety
// over primitive types such as strings and ints.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...as they cannot be implicitly cast to/from the type they wrap. For example, a function that takes a parameter of type Address will not accept a value of type string (and vice versa).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed (heh, that was a pun).

elif item < x then Node(x, insert item left, right) // Call into left subtree.
else Node(x, left, insert item right) // Call into right subtree.

/// Discriminated Unions can also be represented as structs via the 'Struct' attribute.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When would you use this? Why would you prefer to use a struct DU over a reference DU?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed this with a basic statement. There should be some documentation somewhere where we could point to about structs v. reference types for performance, but since it's a bit of a tricky area that's subject to that specific code, I've opted not to explain anything here.

Copy link
Contributor

@smoothdeveloper smoothdeveloper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice showcase of the syntax for main constructs.

///
/// The second line below will fail to compile because of this. Uncomment it to see what happens.
let sampleStructTuple = struct (1, 2, 3)
//let thisWillNotCompile: (int*int) = struct (1, 2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding

//let thisWillCompile: struct (int*int) = struct (1, 2)

?

/// A record is a collection of data items brought together into one object.

/// Records are an aggregate of named values, with optional members (such as methods).
/// They are immutable and have structural equality semantics.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/// They are immutable by default and have structural equality semantics.

///
/// This represents a Binary Search Tree, with one case being the Empty tree,
/// and the other being a Node with a value and two subtrees.
type 'T BST =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use BST<'T> notation to match dotnet syntax?

// https://docs.microsoft.com/en-us/dotnet/articles/fsharp/
//
// To see this tutorial in documentation form, see:
// https://docs.microsoft.com/en-us/dotnet/articles/fsharp/tour
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this URL stable?


// Open namespaces using 'open'
// Open namespaces using the 'open' directive.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

directive? Maybe use "keyword" ?

Copy link
Contributor

@forki forki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great. only couple of minor suggestions

/// Modules are the primary way to organize functions and values in F#. This module contains some
/// basic values involving basic numeric values computed in a few different ways.
///
/// To learn more, see: https://docs.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/modules
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here. we need to make sure it's a stable url

/// Conditionals use if/then/elid/elif/else.
///
/// Note that F# uses whitespace indentation-aware syntax like Python.
/// Note that F# uses whitespace indentation-aware syntax, similar to languages like Python or Ruby.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let string4 = """The computer said "hello world" when I told it to!"""

/// String concatenation is '+'. Also see String.concat, System.String.Join and others.
/// String concatenation is normally done with the '+' operator.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the normally should be removed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normally seems fine here. There are after all other ways of concatenating strings..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It pretty much depends on context. If you do it in a big loop you "normally" want to use a string builder. But I'm fine with keeping it.

/// Many other collection types are available in System.Collections.Generic,
/// System.Collections.Immutable and other libraries.
module ListsAndArrays =
/// Lists are ordered, immutable, singly-linked lists. They are eager in their evaluation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

immutability is a concept that is not used in many languages yet. Can we link to a definition?

Copy link
Contributor Author

@cartermp cartermp Dec 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually something covered in the documentation: https://docs.microsoft.com/en-us/dotnet/articles/fsharp/tour#functions-and-modules

let bindings are also how you bind a value to a name, similar to a variable in other languages. let bindings are immutable by default, which means that once a value or function is bound to a name, it cannot be changed in-place. This is in contrast to variables in other languages, which are mutable, meaning their values can be changed at any point in time. If you require a mutable binding, you can use let mutable ... syntax.

I'm a bit wary about copying in that text (or something like it) into comments, but I agree that it should probably be mentioned near the beginning here and a link to some documentation ought to be provided.

let list1 = [ ]

/// This is a list with 3 elements.
/// This is a list with 3 elements. ';' is used to separate elements.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or line breaks. Please add a sample with line breaks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good feedback

yield System.DateTime(2012, month, day) ]

// Print the first 5 elements of 'daysList' using 'List.take'.
printfn "The first 5 days of 2017 are: %A" (daysList |> List.take 5)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did we already introduce the pipe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about this, and it's kind of difficult to introduce piping (and composition with >>) without also having Lists/Arrays/etc, since those are some of the most natural data structures to process data via a pipeline. I think that if we have pipelines prior to this section with some basic lists then it should be okay.

@KevinRansom
Copy link
Contributor

@cartermp
I will pull this as is. These improvements are great, can you prepare and submit a PR with:

  1. Stable Urls for the links.
  2. A module discussing mutability and immutability.

Thanks

Kevin

@KevinRansom KevinRansom merged commit 68d2f08 into dotnet:master Dec 29, 2016
@forki
Copy link
Contributor

forki commented Dec 29, 2016

Awesome job!

@cartermp
Copy link
Contributor Author

FYI the links are stable - both the docs.ms and MSDN links are backed by a redirect system, so if documents get moved around then it'll get handled appropriately. I'll prepare a module for mutability v. immutability and pipelines.

@forki
Copy link
Contributor

forki commented Dec 29, 2016

That would be the first time Microsoft links are considered stable. ;-) But I trust you on this.

open Microsoft.FSharp.Data.UnitSystems.SI.UnitNames

/// Define a unitized constant
let sampelValue1 = 1600.0<meter>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a typo here sampelValue1

@cartermp cartermp deleted the update-tutorial branch December 30, 2016 00:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants