lucamug/elm-exercises/1.0.1

NOTE: the latest version is 2.0.6

Exercises

Ellie Elements

These are the elements used inside Ellie to build an exercise.

exercise : List Expectation -> Program Flags (Model ()) (Msg ())
import Exercises exposing (..)




-- Write a function `last` that returns
-- the last element of a list.
--
last : List a -> Maybe a
last xs =
    -- Your implementation goes here
    Nothing


main : Program Flags Model Msg
main =
    exercise
        -- Your implementation should pass
        -- these tests
        [ last [ 1, 2, 3, 4 ] == Just 4
        , last [ 1 ] == Just 1
        , last [] == Nothing
        , last [ 'a', 'b', 'c' ] == Just 'c'
        ]
TEA modelExercise msgExercise
-> Program Flags (Model modelExercise) (Msg msgExercise)

If the exercise require The Elm Architecure and tests need to access the Model, it is possible to use exerciseWithTea instead of the simpler exercise. It is the analogue of Browser.element but without flags.

import Exercises exposing (..)




-- Write a function `last` that returns
-- the last element of a list.
--
last : List a -> Maybe a
last xs =
    -- Your implementation goes here
    Nothing


main : Program Flags (Model ModelExercise) (Msg MsgExercise)
main =
    exerciseWithTea
        { tests =
            -- Your implementation should pass
            -- these tests
            \model ->
                [ last [ 1, 2, 3, 4 ] == Just 4
                , last [ 1 ] == Just 1
                , last [] == Nothing
                , last [ 'a', 'b', 'c' ] == Just 'c'
                ]
        , init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }


-- Following the definitions of
-- init, view, update, and subscriptions.
type alias Flags =
{ index : String
, exerciseData : String
}

Flags are the way to pass details about the exercises to the page.

They can be either loaded from external scripts, like in this example:

(HTML)

<script src="https://elm-exercises.netlify.app/index.js"></script>
<script src="https://elm-exercises.netlify.app/001.js"></script>
<script src="https://elm-exercises.netlify.app/start.js"></script>

Or they can be hard coded, like in this example (See ExerciseData for a detailed explanation of the fields):

(JavaScript)

var app = Elm.Main.init({
  node: document.getElementById("elm"),
  flags: {
    index: JSON.stringify([]),
    exercise: JSON.stringify(
      { id: 1            // Exercise ID
      , title: ""        // Title of the exercise
      , difficulty: Easy // Easy | Medium | Hard | Undefined
      , problem: ""      // Details of the problem to be solved
      , tests: []        // List of tests
      , hints: []        // List of hints
      , solutions: []    // List of solutions
      , ellie: ""        // Ellie ID
      }
    )
  }
});
type alias Model modelExercise =
InternalModel modelExercise

Internal. Exposed to be used in type signatures

type Msg msgExercise

Internal. Exposed to be used in type signatures

ExerciseData

type alias ExerciseData =
{ id : Int
, ellieId : String
, title : String
, difficulty : Difficulty
, problem : String
, tests : List String
, hints : List String
, dummySolution : String
, solutions : List String
}

This record define an exercise.

  • id A sequencial number. It should be the same as the file name. Numbers from 1 to 99 are reserved to the Ninety-nine Problems, Solved in Elm.
  • ellieId, The id from the Ellie url
  • title of the exercise. Keep it concise and explicative
  • difficulty level of the exercise
  • problem, a detailed description of the problem
  • tests
  • hints, a list of suggestions that the user can unhide to help him in the process of finding a solution
  • dummySolution, A placeholder for the solution. Be sure that the type signature is correct and that it compiles. Use dummy values as returned values. For example if the function return List a, you can return []. If the function return Maybe a you can return Nothing, etc.
  • solutions, a list of possible solutions
= Easy
| Medium
| Hard
| Undefined

Tests

These are the same tests of elm-explorations/test. Refer to that package for the documentation.

type alias Expectation =
Expectation

In this package I change Expect.Expectation to Expectation

equal : a -> a -> Expectation
notEqual : a -> a -> Expectation
all : List (subject -> Expectation) -> subject -> Expectation
lessThan : comparable -> comparable -> Expectation
atMost : comparable -> comparable -> Expectation
greaterThan : comparable -> comparable -> Expectation
atLeast : comparable -> comparable -> Expectation
FloatingPointTolerance
within : FloatingPointTolerance -> Float -> Float -> Expectation
notWithin : FloatingPointTolerance -> Float -> Float -> Expectation
true : String -> Bool -> Expectation
false : String -> Bool -> Expectation
ok : Result a b -> Expectation
err : Result a b -> Expectation
equalLists : List a -> List a -> Expectation
equalDicts : Dict comparable a -> Dict comparable a -> Expectation
equalSets : Set comparable -> Set comparable -> Expectation
pass : Expectation
fail : String -> Expectation
onFail : String -> Expectation -> Expectation

For internal use

TEA modelExercise msgExercise
-> Msg msgExercise
-> Model modelExercise
-> ( Model modelExercise, Cmd (Msg msgExercise) )
TEA modelExercise msgExercise
-> Model modelExercise
-> Element (Msg msgExercise)
TEA modelExercise msgExercise
-> Flags
-> ( Model modelExercise, Cmd (Msg msgExercise) )
onlyTests : List Expectation -> TEA () ()
type alias TEA modelExercise msgExercise =
{ init : ( modelExercise, Cmd msgExercise )
, view : modelExercise -> Html msgExercise
, update :
msgExercise -> modelExercise -> ( modelExercise, Cmd msgExercise )
, subscriptions : modelExercise -> Sub msgExercise
, tests : modelExercise -> List Expectation
}
type alias Index =
{ id : Int
, title : String
, difficulty : Difficulty
, ellieId : String
}

Codecs

codecExerciseData : Codec ExerciseData
codecIndex : Codec Index