lucamug / elm-exercises / Exercises

Ellie Elements

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

exercise : { tests : List Test, portLocalStoragePop : (String -> Msg ()) -> Platform.Sub.Sub (Msg ()), portLocalStoragePush : String -> Platform.Cmd.Cmd (Msg ()) } -> Platform.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

tests : List Test
tests =
    -- 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'
    ]

main : Program Flags (Model ()) (Msg ())
main =
    exercise
        { tests = tests
        , portLocalStoragePop = portLocalStoragePop
        , portLocalStoragePush = portLocalStoragePush
        }

port portLocalStoragePop : (String -> msg) -> Sub msg

port portLocalStoragePush : String -> Cmd msg

exerciseWithView : { tests : List Test, portLocalStoragePop : (String -> Msg ()) -> Platform.Sub.Sub (Msg ()), portLocalStoragePush : String -> Platform.Cmd.Cmd (Msg ()), view : Element () } -> Platform.Program Flags (Model ()) (Msg ())

exerciseWithTea : { init : ( modelExercise, Platform.Cmd.Cmd msgExercise ), view : Maybe (modelExercise -> Element msgExercise), update : msgExercise -> modelExercise -> ( modelExercise, Platform.Cmd.Cmd msgExercise ), subscriptions : modelExercise -> Platform.Sub.Sub msgExercise, tests : modelExercise -> List Test, portLocalStoragePop : (String -> Msg msgExercise) -> Platform.Sub.Sub (Msg msgExercise), portLocalStoragePush : String -> Platform.Cmd.Cmd (Msg msgExercise) } -> Platform.Program Internal.Data.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 =
Internal.Data.Flags

Flags are used 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/js/index.js"></script>
<script src="https://elm-exercises.netlify.app/js/001.js"></script>
<script src="https://elm-exercises.netlify.app/start.js"></script>

You can check the forrmat of the data in these files as reference:

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 =
Internal.Data.Model modelExercise

Internal. Exposed to be used in type signatures


type alias Msg msgExercise =
Internal.Data.Msg msgExercise

Internal. Exposed to be used in type signatures

ExerciseData


type alias ExerciseData =
Internal.Data.ExerciseData


type alias Difficulty =
Internal.Data.Difficulty

difficulty : { easy : Internal.Data.Difficulty, hard : Internal.Data.Difficulty, medium : Internal.Data.Difficulty, undefined : Internal.Data.Difficulty }

Helpers

attrsButton : List (Element.Attribute msg)

yourImplementationGoesHere : String

Tests

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


type alias Test =
Expectation

Rename Expectation to Test as they can be run immediately in this context

equal : a -> a -> Test

notEqual : a -> a -> Test

all : List (subject -> Test) -> subject -> Test

lessThan : comparable -> comparable -> Test

atMost : comparable -> comparable -> Test

greaterThan : comparable -> comparable -> Test

atLeast : comparable -> comparable -> Test


type alias FloatingPointTolerance =
Expect.FloatingPointTolerance

within : FloatingPointTolerance -> Basics.Float -> Basics.Float -> Test

notWithin : FloatingPointTolerance -> Basics.Float -> Basics.Float -> Test

true : String -> Basics.Bool -> Test

false : String -> Basics.Bool -> Test

ok : Result a b -> Test

err : Result a b -> Test

equalLists : List a -> List a -> Test

equalDicts : Dict comparable a -> Dict comparable a -> Test

equalSets : Set comparable -> Set comparable -> Test

pass : Test

fail : String -> Test

onFail : String -> Test -> Test

For internal use

update : TEA modelExercise msgExercise -> Msg msgExercise -> Model modelExercise -> ( Model modelExercise, Platform.Cmd.Cmd (Msg msgExercise) )

viewElement : Internal.Data.TEA modelExercise msgExercise -> Internal.Data.Model modelExercise -> Element (Internal.Data.Msg msgExercise)

viewElementAttrs : Internal.Data.Model modelExercise -> List (Element.Attribute (Internal.Data.Msg msgExercise))

init : TEA modelExercise msgExercise -> Internal.Data.Flags -> ( Model modelExercise, Platform.Cmd.Cmd (Msg msgExercise) )


type alias TEA modelExercise msgExercise =
Internal.Data.TEA modelExercise msgExercise


type alias Index =
Internal.Data.Index

Codecs

codecIndex : Codec Internal.Data.Index

codecExerciseData : Codec Internal.Data.ExerciseData