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.
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
}
)
}
});
Internal.Data.Model modelExercise
Internal. Exposed to be used in type signatures
Internal.Data.Msg msgExercise
Internal. Exposed to be used in type signatures
Internal.Data.ExerciseData
Internal.Data.Difficulty
difficulty : { easy : Internal.Data.Difficulty, hard : Internal.Data.Difficulty, medium : Internal.Data.Difficulty, undefined : Internal.Data.Difficulty }
attrsButton : List (Element.Attribute msg)
yourImplementationGoesHere : String
These are the same tests of elm-explorations/test. Refer to that package for the documentation.
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
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
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) )
Internal.Data.TEA modelExercise msgExercise
Internal.Data.Index
codecIndex : Codec Internal.Data.Index
codecExerciseData : Codec Internal.Data.ExerciseData