Haskell Learners' Group (Session 2)
By Walker Malling and Richard Cook, 2018/5/2
A recap of what we talked about during the second meeting of the Haskell Learners’ Group in Seattle
We had about three additional attendees which was pretty nice. Most of last month’s attendees returned which was also very encouraging! We talked about the Slack channel and how there is been much lively and fun discussion. Walker set the tone for the meeting: functions, functions, functions!
Richard briefly reviewed our last session, touching on the essentials of the haskell development environment and the anatomy of a Stack project. Refer to last month’s minutes!
Richard worked from some of his Beginning Practical Haskell material on the subject of functions. Talking points included:
What is functional programming?
One possible answer: Programming that emphasizes functions over everything else
How do values and functions relate in Haskell?
One possible answer: Functions are values in Haskell; the converse is not necessarily true: not all values are also functions, though they certainly look (syntactically, at least) like nullary functions (functions in one argument)
Richard discussed visual elements of Haskell programs
- Module declarations
- Import statements
- Top-level function declarations
- Function type signatures
- Have not yet covered type declarations
a = 5 -- is a declaration a = 6 -- not a mutation, an instance of name shadowing (creating a new nested scope)
Richard Rodseth correctly mentioned that we should emphasize that declarations in Haskell are equations
Richard (Cook) valiantly tries to say “is” instead of “equals” and to avoid using the word “assign” altogether
Brief (but necessary!) Tangent on Types & Type Signatures
We considered the difference between
a + 1 and
a + 1.1.
a + 1.1 has type
:: Fractional a => a
a + 1 has type
:: Num a => a
We used the
:info command to inspect the
Fractional type classes.
:info Num and
(We duscussed the difference between a Type and a Typeclass…)
You can implement your own Num typeclass if you want, as long as you adhere to the requirements of the typeclass properties, e.g. you implement all its methods
Introduction to concrete vs. polymorphic types
Note on the difference between Haskell and other languages: Haskell’s typeclasses are unlike Java interfaces and abstract classes (which are dynamic dispatches at runtime; typeclasses are resolved at compile time)
Fucntions, take 2 (return from tangent on types!)
Function declarations declare one or more arguments identified by name on the left-hand side of the equation
All Haskell functions are actually functions in one argument and multiple arguments in declarations are syntactic sugar
We breifly discussed currying (all Haskell functions are automatically curried)
We Talked about parentheses and how Haskell can simulate “parentheses” languages using tuples
Richard also mentioned CodeWorld’s “parentheses” variant of Haskell
addIntegers for adding numbers
add x y = x + y is the same as
add = \x y = x + y
You can (and we did) prove that by getting the type signature of each in
“Applying f to x” looks like this is Haskell:
f x y
Pedagogical notes: At this point we got sidetracked by a discussion on
Numand related type classes. It might make sense in the future to introduce fully monomorphic functions at first to avoid being sidetracked by type variables and type classes. The problem there is teh lack of sensible monomorphic functions. All common arithmetic operations and functions are defined in terms of
Floatingetc. Perhaps use a custom simplified prelude? Even strings are problematic, as we then have to deal with lists and explain that
We talked about name shadowing particularly in GHCi
Pedagogical notes: This is confusing especially given the immutability of Haskell variables. Of course, immutability is one of Haskell’s primary selling points, so some thought needs to go into how to teach this
Richard stated that accessing shadowed names is possible but couldn’t remember how; Jake reported back how to do it (see)
Richard Introduced following function concepts
- Function application and how whitespace is effectively the function application operator with highest precedence of any function
- Composition and the
- Use of parentheses for explicit precedence
- Higher-order functions (i.e. Functions that take other functions)
- Partial application, which some claim is an illusion!
Richard demonstrated the basics of
lists, included the
- Lists are declared with
- Lists can contain any type, but all members of a list must be of the same type
- brackets are usually Arrays or Vectors in other languages, but there are important differences between those data types and Haskell lists.
- Lists of different lenghts still have the same type
Mentioned also that any type with an
Enum instance can be used to define a range.
We determined that
[False..True] doesn’t parse but
[False .. True] does (conflicts with qualified name syntax)
Started talking about generating lists of days of the month
More Notes on a Haskell program:
- All programs need a Main module, look at the module header
mainfunction typically has type signature
- You can export more than 1 function from a module
- You can specify which functions to export; by default all top level declarations are exported
- Discussion of
IO (), or
Unit: returns no value
- Can be
IOof anything, but any value is ignored and does not affect how program returns to the shell
- Programs typically use
exitSuccessactions to report status codes to the shell
- Richard Emphasized that we talk about
IOactions represent an imperative program that is executed by the Haskell runtime
IOis a mysterious, magical type class
“Haskell lifehacks” vol 1
Building in loop with file watcher
stack build --file-watch --exec hello-seattle
hello-seattle is the binary (the name of the stack project).
Danielle asked: how do you identify which imported module is failing when writing a program
You can use
:info to see all the places the module is referenced, and where the symbol is defined
More questions about IDE integration (i.e., for automatically importing libraries) and import lists
The style of
import statements can affect discoverability of symbols
Explicit imports (e.g.
import Data.List (intercalate)) make it very clear where a given symbol comes from… but they’re kinda noisy and verbose
IDE tooling could help with keeping these lists under control and the compiler can warn about unused imports
Can also install Hoogle locally (ask Richard about his GHCi
:hoogle command if you want more information)
Hoogle supports search by symbol as well as search by type signature
“Haskell Lifehacks” vol 2
You can set a custom search engine in Chrome and bind it to a key of your choosing, such that when the address bar is in focus, hitting
h (for example) will activate hackage.haskell.org, and anything you enter into the address bar thereafter will by piped into the hackage search engine.
You can (reputedly) do this with Firefox as well, but this was not demostrated.
Jake suggested we try an exercise:
Implement a function
datesInMonth :: String -> Int -> [String]which takes the name of a month (“May”) and the number of days in that month (31), and returns a list of all the dates in that month
(["May 1", ..., "May 31"]).
Richard did some live coding, until we hit 8pm and had to take the show on the road.
There was some brief discussion as we were leaving of appropriate projects or outcomes from these meetings. Walker and Richard hope to present something appealing to all attendees shortly!