More exercises using abilities

๐Ÿ““Implement functions with calls to Ability operations

Given the type signatures below, implement the functions to satisfy the compiler using the request operations of the Ability or functions found in.base

getWithAbort : a -> Map a b ->{Abort} b
getWithAbort key map = base.todo "implement me!"
โœจHint: how do I see the request operations of an ability?
โœจHint: how do I see the request operations of an ability?
In the UCM, you can enterview Abortto see the ability definition. The function signatures after thewherekeyword are the request operations.
๐Ÿ”‘Answer:
๐Ÿ”‘Answer:

Using theOptional.toAbortfunction.

getWithAbort : a -> Map a b ->{Abort} b
getWithAbort key map = toAbort (get key map)

Pattern matching onOptional

getWithAbort : a -> Map a b ->{Abort} b
getWithAbort key map =
    match get key map with
      Some a -> a
      None   -> abort

๐Ÿ““Implement functions with Ability operations

rangeAverage : Nat ->{Store [Nat]} Float
rangeAverage n = base.todo "implement me"

Using theStoreability to keep track of aListof numbers, write a function which takes in some numbernofNatas an upper bound of a list from0up to (but not including)nand returns the average of the final list.

So, given an upper value of5,the average produced would be the average of[0, 1, 2, 3, 4],or2.0

๐Ÿ”‘Answer
๐Ÿ”‘Answer

One possible solution is as follows:

averageOfRange : Nat ->{Store [Nat]} Float
averageOfRange n =
  use Float / fromNat
  use List +:
  use Nat + ==
  go = cases
    i
      | i == n     ->
        myList = Store.get
        listSize = List.size myList
        sum =
          lib.base.data.List.foldLeft
            (acc element -> element + acc) 0 myList
        fromNat sum / fromNat listSize
      | otherwise  ->
        Store.modify (currentList -> i +: currentList)
        go (i + 1)
  go 0

๐Ÿ““Apply a handler to a function requiring abilities

Check out the functions in thebaselibraries for operating onStoreand see if you can apply a handler to the function you wrote previously forfinding the average of a range.The handler should help you return theFloatvalue to check your function.

โœจHint: What kind of function am I looking for?
โœจHint: What kind of function am I looking for?
You'll want a function whose return type does not requireStorein curly braces in its final value. The handler should run or "interpret" the program which performs aStoreability into another value.
๐Ÿ”‘Answer:
๐Ÿ”‘Answer:

One possible solution is as follows:

handleAverageOfRange : Float
handleAverageOfRange = withInitialValue [] '(averageOfRange 5)

withInitialValuehandles a function that requires theStoreability by setting the initial state of theStore.


๐Ÿ““Debug an abilities issue

The following watch expression is failing to typecheck.

randomIndex : [Nat] -> '{Random, Abort} Nat
randomIndex list = 'let
  n = List.size list
  if n === 0 then abort else Random.natIn 0 n

> toOptional! (Random.lcg 7 (randomIndex [1,2,3]))

The UCM error is:

The 2nd argument to `(<|)`

            has type:  Nat
      but I expected:  Unit ->{g, Abort} ๐•ฉ

    142 | randomIndex : [Nat] -> '{Random, Abort} Nat
    143 | randomIndex list = 'let
    144 |   n = List.size list
    145 |   if n === 0 then abort else Random.natIn 0 n
    146 |
    147 | > toOptional! (Random.lcg 7 (randomIndex [1,2,3]))

Why is the error occurring and how might it be corrected?

๐Ÿ”‘Answer:
๐Ÿ”‘Answer:

One possible solution is as follows:

randomIndex : [Nat] -> '{Abort, Random} Nat randomIndex list = do n = List.size list if n === 0 then abort else base.abilities.Random.natIn 0 n toOptional! '(lib.base.abilities.Random.lcg 7 (randomIndex [1, 2, 3]))
โงจ

toOptional!is a function which expects a delayed computation which performs theAbortability. The entire expression will need a'symbol in front of the call tolib.base.abilities.Random.lcg