Haskell Study Group - 1st month - getting started

37 views
Skip to first unread message

Harold Carr

unread,
Sep 15, 2014, 11:12:54 PM9/15/14
to lambda-l...@googlegroups.com
Hello all,

It sure is quiet!   I guess that means everyone is doing find studying Haskell on their own - no need to ask questions of the group?

UPENN:

I noticed that the contents of the UPENN course link:


doesn't have all the assignments for the 12 weeks - because they are giving the course again right now using the same link.

The first homework is still exactly like the previous one, so we are still good to go.

NICTA:

Everyone should study Id.hs , Optional.hs and Vailidation.hs in detail.

The actual first exercises start in List.hs


LET'S TALK

Assuming people are making progress, either let's start asking questions of each other, or let's start sharing/comparing our solutions.

Regards,
Harold

Ben Mabey

unread,
Sep 16, 2014, 12:38:30 AM9/16/14
to lambda-l...@googlegroups.com

LET'S TALK

Assuming people are making progress, either let's start asking questions of each other, or let's start sharing/comparing our solutions.


I started on the UPENN course on Saturday and did the first part of HW1 (the credit card validation).  I'll share my solution for comparison and critique:

https://gist.github.com/bmabey/b4a1494381fd06353685

(If people fork my solution to enter their solutions we can keep track of everyone's by looking at the root gist.)

One thing I did want while writing my solution was Clojure's threading operator (macro).  The threading operator is like the thrush combinator[1] but uses code rewrites so it is slightly different than normal function composition. The main idea though is that you can write code like:

(defn validate [x]
  (-> x to-digits double-every-other sum-digits (mod 10) zero?))

Contrast that to regular function composition that reads "backwards" and the mod operator is on the outside of everything else:

validate
x = (mod ((sumDigits . doubleEveryOther . toDigits) x) 10) == 0

I found this SO talking about how to do something similar in Haskell w/Control.Arrow or rolling your own function:

https://stackoverflow.com/questions/9545816/is-there-a-name-for-a-function-that-takes-a-piece-of-data-and-a-list-of-function

How common is Control.Arrow or similar constructs used in Haskell code?  The threading operator is idiomatic in clojure so I'm trying to get feel for how common that pattern is in Haskell.

-Ben

p.s. Jay McCarthy has great post on doing the threading macro and more advanced variants using Racket's syntax parameters which I found enlightening: https://jeapostrophe.github.io/2013-05-27-stxparam-post.html

1. http://blog.fogus.me/2010/09/28/thrush-in-clojure-redux/

Paul English

unread,
Sep 16, 2014, 1:48:19 AM9/16/14
to lambda-l...@googlegroups.com
I’ve gotten through hw1 & 2, and most of #3.


I’ve just been trying to stick to the basics, and haven’t really branched into much if any function composition. I’m very new to Haskell and have found myself confused in a few spots. I feel like I’m using too many parentheses (says the guy who uses Clojure), and would also like to have a threading operator like Ben mentions.

It’s nice to have gotten through a few decent working functions, and any review on them would be welcomed. It looks like in the coming weeks we’ll cover a lot of the things that I could probably use to clean these up.

I did find the `:reload` command in ghci, and really like that. I had a quick look at some of the testing tools available in Haskell, but didn’t make use of any of them. What’s a good tool for testing in Haskell, and is there any kind of autotest tool that incorporates `:reload` or similar?

--
You received this message because you are subscribed to the Google Groups "Lambda Lounge Utah" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lambda-lounge-...@googlegroups.com.
To post to this group, send email to lambda-l...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ben Mabey

unread,
Sep 16, 2014, 10:44:55 AM9/16/14
to lambda-l...@googlegroups.com

> I did find the `:reload` command in ghci, and really like that. I had
> a quick look at some of the testing tools available in Haskell, but
> didn’t make use of any of them. What’s a good tool for testing in
> Haskell, and is there any kind of autotest tool that incorporates
> `:reload` or similar?
>

I've heard good things about Tasty: http://documentup.com/feuerbach/tasty
It allows you to run all types of tests in a single suite.

-Ben

Harold Carr

unread,
Sep 16, 2014, 11:19:48 AM9/16/14
to lambda-l...@googlegroups.com
My solutions to UPENN hw01 are:


Note: my solutions contain unit tests using Test.HUnit and some utilities I wrote:


So, when I make changes, I just :r (reload) and run, in this case, hw01 to ensure all tests still pass.

Levi Pearson

unread,
Sep 16, 2014, 12:21:22 PM9/16/14
to lambda-l...@googlegroups.com
On Mon, Sep 15, 2014 at 10:38 PM, Ben Mabey <b...@benmabey.com> wrote:

> One thing I did want while writing my solution was Clojure's threading
> operator (macro). The threading operator is like the thrush combinator[1]
> but uses code rewrites so it is slightly different than normal function
> composition. The main idea though is that you can write code like:
>
> (defn validate [x]
> (-> x to-digits double-every-other sum-digits (mod 10) zero?))
>
> Contrast that to regular function composition that reads "backwards" and the
> mod operator is on the outside of everything else:
>
> validate x = (mod ((sumDigits . doubleEveryOther . toDigits) x) 10) == 0
>
> I found this SO talking about how to do something similar in Haskell
> w/Control.Arrow or rolling your own function:
>
> https://stackoverflow.com/questions/9545816/is-there-a-name-for-a-function-that-takes-a-piece-of-data-and-a-list-of-function

I have used the foldr technique in real code that needs to apply a
dynamic number of validation functions to a user-supplied value, but
if the functions to apply are known statically then it'd best to
directly compose them. This leaves more optimization opportunities
open to the compiler.

> How common is Control.Arrow or similar constructs used in Haskell code? The
> threading operator is idiomatic in clojure so I'm trying to get feel for how
> common that pattern is in Haskell.

Control.Arrow combinators are used frequently by people trying
extra-hard to write point-free code (i.e. building functions by
composing combinators instead of lambdas with arguments) and not much
at all by people who use a more traditional Haskell style. I'd
recommend against them at first, but it's good to know about them
eventually as you will find a few examples in the wild.

When you're dealing with a function where the arguments are in the
"wrong" order for convenient composition, there are a couple of ways
to handle it. First, there's the `flip` combinator that reverses the
order of the arguments: (flip mod 10). Second, you can take
advantage of two syntactic features--using backticks to turn a named
function into an operator and operator sections--to create a
partially-applied function: (`mod` 10). Using this technique, you'd
get something like the following:

validate = (== 0) . (`mod` 10) . sumDigits . doubleEveryOther . toDigits

Haskell programmers have traditionally found function composition
order to be more natural to use than the "threading" order created by
Clojure's -> macro, so there aren't any standard ways of creating
them. Many Haskell-hosted DSLs have such a feature, but I'd recommend
trying to get used to normal function composition order, as it's by
far the most commonly used idiom in Haskell.

Levi Pearson

unread,
Sep 16, 2014, 12:40:27 PM9/16/14
to lambda-l...@googlegroups.com
On Mon, Sep 15, 2014 at 11:47 PM, Paul English <pa...@onfrst.com> wrote:
> I’ve gotten through hw1 & 2, and most of #3.
>
> 1 - https://gist.github.com/log0ymxm/7de23637c05dec0f43de
> 2 - https://gist.github.com/log0ymxm/2ca31bda9244a56e8ab6
> 3 - https://gist.github.com/log0ymxm/8112b4f822b0060b9f62
>
> I’ve just been trying to stick to the basics, and haven’t really branched
> into much if any function composition. I’m very new to Haskell and have
> found myself confused in a few spots. I feel like I’m using too many
> parentheses (says the guy who uses Clojure), and would also like to have a
> threading operator like Ben mentions.

Careful application of function composition operator (.) and the
right-associative function application operator ($) are the standard
way to remove parentheses in Haskell. Whether it's good style or not
to aim for fewer parentheses is a point of difference among popular
Haskell styles. Personally, I use function composition heavily and $
sparingly; I think parentheses are a clearer way to show that standard
precedence is being overridden, but I dislike deeply nested
parentheses in Haskell or parens that span multiple lines. Here's an
example from your first gist:

doubleEveryOther x = reverse (doubleRev (reverse x))

That can be rewritten:

doubleEveryOther x = (reverse . doubleRev . reverse) x

And the parens can be eliminated by using $, which is low-precedence,
right-associative function appliction:

doubleEveryOther x = reverse . doubleRev . reverse $ x

And via the eta-reduction rule (the name comes from the traditional
lambda calculus evaluation rules, if you're not familiar with it), you
can eliminate the parameter:

doubleEveryOther = reverse . doubleRev . reverse

There are a couple of other places where you can eliminate parens just
by trusting the precedence rules in the grammar. I haven't got all of
them memorized, but the key thing to remember is that standard
function application is left-associative and is the highest precedence
operation in the grammar. So:

f x + g y

is equivalent to:

(f x) + (g y)

for any operator where + is there, including comparison, equality, and
composition operators. Getting a feel for this precedence rule in
particular will help *tremendously* when reading and writing idiomatic
Haskell code.

--Levi

Harold Carr

unread,
Sep 16, 2014, 4:04:38 PM9/16/14
to lambda-l...@googlegroups.com
In my solution to `toDigits` I use `unfoldr` - it is kind of the dual of `foldr` - where foldr is used to reduce a list to some other value, unfoldr is used to take some value and turn it into a list.

I use `foldr` to implement `sumDigits` in one pass.

For `doubleEveryOther` I do something similar to what Levi showed using a fold - but I have used an explicit recursion.  I like Levi's solution better.

BTW: Levi, your comments/advice are great!

harol...@gmail.com

unread,
Sep 16, 2014, 7:18:41 PM9/16/14
to Ben Mabey, lambda-l...@googlegroups.com
see below:
 
I started on the UPENN course on Saturday and did the first part of HW1 (the credit card validation).  I'll share my solution for comparison and critique:

https://gist.github.com/bmabey/b4a1494381fd06353685

(If people fork my solution to enter their solutions we can keep track of everyone's by looking at the root gist.)

 
I would suggest that we keep the discussion either in the mailing list or in a wiki page for upenn hw01.   Otherwise the discussion will be spread out all over the place.


John Hatfield

unread,
Sep 17, 2014, 1:00:59 AM9/17/14
to lambda-l...@googlegroups.com
Finally getting started - I just finished the upenn hw1 credit card exercises here: 

let me know if you have any suggestions. I'll check out everyone else's solutions and do the same - then its on to hanoi...

Thanks,
John

harol...@gmail.com

unread,
Sep 17, 2014, 12:47:23 PM9/17/14
to John Hatfield, lambda-l...@googlegroups.com
Hello John,

I like your point-free `validate`

I think your `doubleEveryOther` is incorrect.  The spec says to double every other - beginning from the RIGHT.

Regards,
Harold

harol...@gmail.com

unread,
Sep 17, 2014, 1:12:58 PM9/17/14
to John Hatfield, lambda-l...@googlegroups.com
Hello John,

A very minor point: in your `validate` you use `lastDigit` instead of an explicit (`mod` 10).

For a small program that seems fine.  But for a large program where one would be reading the specification of validate, then using `lastDigit` would be confusing.  I would use an explicit MOD.

Regards,
H


Scott Nielsen

unread,
Sep 17, 2014, 9:06:00 PM9/17/14
to lambda-l...@googlegroups.com
Here is my fork of Ben’s gist.


I tried to make the credit card stuff as point free as I could, not because I am convinced it is better, but just to play around.
I think it turned out well though.

Scott

Reply all
Reply to author
Forward
0 new messages