If you need some inspiration for using and writing abilities, we've curated a list of exercises fromthe Unison language Exercism trackthat either benefit from the one or more of the abilities found in`base`

,or that include stubs for writing your own ability handlers. The descriptions below make note of how the problem might benefit from using abilities, while full instructions, tests, and stub files can be found by following the links in each section!

๐Majority element

The majority element is one which takes up over half of the space in a collection. Given a list of elements representing the colors, return the color found as the majority, otherwise indicate that no majority has been found.

While you can implement the function under test in any way you choose, we've provided a few stubs which use the`Store`

ability. For additional practicewritinghandlers, we've given a handler stub called`runWith`

to implement.`runWith`

returns both the result of running the function which uses the Store ability and the final state of the Store.

This exercise is about implementing basic Stream ability operations. Writing your own handlers for common functional combinators like`map`

,`flatMap`

and`filter`

.

`Ask`

ability in`Stream.pipe`

`Ask`

ability in`Stream.pipe`

`structural ability Ask a`

`structural ability Ask a where lib.base.abilities.Ask.ask : {Ask a} a`

Here's another example ability,`Ask`

,which provides one operation,`ask`

,for requesting a value of type`a`

from whatever code handles the ability.

`provide`

is a handler for ask which provides a constant value.

A common usage of`Ask`

is to avoid needing to pass around common configuration settings, just`provide myConfig 'myMain`

to make myConfig available anywhere in`myMain`

with a call to`ask`

.

Computations that use`Ask`

can also be thought of as stream consumers. Try writing a function`pipe`

,which can be used to statefully transform a stream:

In implementing this, you'll have a handler that matches on a`Request {Ask a, Stream b} r`

.Handlers that match on multiple abilities at once like this are sometimes called "multihandlers."" There's nothing special you need to do in Unison to write multihandlers; just match on the operations from more than one ability in your handler!

Once you've written`fundamentals.abilities.abilityExercises.Stream.pipe`

,try writing`Stream.map`

,`Stream.filter`

,and`Stream.take`

using`fundamentals.abilities.abilityExercises.Stream.pipe`

.

Given a string containing brackets`[]`

,braces`{}`

,parentheses`()`

,or any combination thereof, verify that any and all pairs are matched and nested correctly.

There are many ways to accomplish this exercise, but we've provided some additional stubs for folks who'd like to practice writing their own ability handlers.

The signature for the`checkBalance`

helper function given for this exercise makes use of an ability requirement,`{Stack}`

.The Stack ability is defined for you, but the handler,`Stack.run`

is not! If you chose, you can implement the Stack.run, checkBalance, and isPaired function. The tests will run even if you choose not to implement this exercise with abilities.

๐Change

Correctly determine the fewest number of coins to be given to a customer such that the sum of the coins' value would equal the correct amount of change.

This exercise doesn't explicitly require abilities, but many folks have used the`Store`

ability for memoization when optimizing their solution.

๐Zipper

Write a Zipper that allows you to navigate through a binary tree data structure.

There are many ways to accomplish this exercise, but we've tailored this exercise for folks who'd like to practice writing their own Zipper ability.

The Zipper ability itself is defined for you, but you'll need to implement the handler that allows it to navigate through the given binary tree data structure.

๐Zebra Puzzle

Given a set of possible attributes of a number of houses and a series of constraints, find the house that whose resident owns a zebra.

This problem offers an opportunity to use the`Each`

ability for non-determinism in the`base`

library.

You might also want choose to use an ability for optimizing the search space when finding who owns the zebra. ๐ค

## 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!"
```

`view Abort`

to see the ability definition. The function signatures after the`where`

keyword are the request operations.Using the`Optional.toAbort`

function.

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

Pattern matching on`Optional`

```
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 the`Store`

ability to keep track of a`List`

of numbers, write a function which takes in some number`n`

of`Nat`

as an upper bound of a list from`0`

up to (but not including)`n`

and returns the average of the final list.

So, given an upper value of`5`

,the average produced would be the average of`[0, 1, 2, 3, 4]`

,or`2.0`

One possible solution is as follows:

`averageOfRange : Nat ->{Store [Nat]} Float`

```
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 = 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 the`base`

libraries for operating on`Store`

and 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 the`Float`

value to check your function.

One possible solution is as follows:

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

`withInitialValue`

handles a function that requires the`Store`

ability by setting the initial state of the`Store`

.

๐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?

One possible solution is as follows:

`toOptional!`

is a function which expects a delayed computation which performs the`Abort`

ability. The entire expression will need a`'`

symbol in front of the call to`lcg`