Skip to content

discussion: Should we provide type signatures with the exercises? #181

@rbasso

Description

@rbasso

We can provide exercises with a stub solution, like this one:

module LeapYear (isLeapYear) where

isLeapYear :: Integer -> Bool
isLeapYear year = undefined

I believe we could make the Haskell track more enjoyable and accessible for beginners adding stubs to all exercises. This could save users from inspecting the test suites to figure out what they need to implement.

I see two possible objections to this:

  1. Figuring out what is the exercise is part of the exercise
  2. Some tests that currently allow polymorphic solutions would have to be restricted

About 1, I think it is too difficult for beginners, and it gets easy and boring after a while. As an example, look at our first test suite:

{-# OPTIONS_GHC -fno-warn-type-defaults #-}

import Control.Monad (unless)
import System.Exit   (exitFailure)

import Test.HUnit
    ( (~:)
    , (~=?)
    , Counts (failures, errors)
    , Test   (TestList)
    , runTestTT
    )

import LeapYear (isLeapYear)

main :: IO ()
main = do
         counts <- runTestTT isLeapYearTests
         unless (failures counts == 0 && errors counts == 0) exitFailure

isLeapYearTests :: Test
isLeapYearTests = TestList $ map test cases
  where
    test (label, year, expected) = label ~: isLeapYear year ~=? expected
    cases = [ ("leap year"                  , 1996, True )
            , ("standard and odd year"      , 1997, False)
            , ("standard even year"         , 1998, False)
            , ("standard nineteenth century", 1900, False)
            , ("standard eighteenth century", 1800, False)
            , ("leap twenty fourth century" , 2400, True )
            , ("leap y2k"                   , 2000, True ) ]

There is no single mention of the argument type of isLeapYear. Is it Int, Integer or any Integral? Should I choose? Which one is better?

I don't see what people are learning reading tests like this, specially after repeating it 70 times.

The problem with 2 is that, by allowing a "polymorphic solution/library", we end up writing unidiomatic tests, and we expose users to bad coding practices. We should allow freedom on how to implement a solution, but the interface is what defines a problem, and the problem should be well defined and clearly stated.
Also, in real life, we don't usually try to write a library to fit already written tests without any type annotations.

In #143 we met some problems related to this flexible approach. At the time It sounded like a good idea to allow it, now I believe it's undesirable from a pedagogical point of view.

Currently, only those exercises have stub solutions:

  • all-your-base
  • forth
  • lens-person
  • list-ops
  • rna-transcription
  • zipper

For the first exercises, we have more than 800 visible solutions, but that drops rapidly to 10 solutions in the later ones. Maybe we can get people to go a little further giving a little help with stub solutions! 😄

Should we add stubs for other exercises?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions