A few exercises relevant to values and functions.
π Exercise: Understand parentheses in type signatures
List.zipWith
is a function which takes in two lists and a function which operates on the elements in both lists sequentially until the end of one of the lists is reached.
A mysterious parenthesis blight has wiped away the necessary parentheses to communicate this.
blightedZipWith: a -> b -> c -> [a] -> [b] -> [c]
Where should the parentheses in the type signature go? Where should the implied parentheses go for this type signature?
threeArgumentFunction : Nat -> Text -> Boolean -> Nat
Is analogous to
threeArgumentFunction: Nat -> (Text -> (Boolean -> Nat))
It's easy to conflate the order of function application (the order in which a function is called) with the order of its type notation. Here we're looking for a description of where to draw the implied and actual parentheses for how the function arrow ->
works in a type signature.
The required parentheses are as follows:
zipWith: (a -> b -> c) -> [a] -> [b] -> [c]
The first argument to List.zipWith
is a function with two arguments a
and b
. Lists [a]
and [b]
are the two lists being zipped, and [c]
is the return type of the over all function.
Adding the implied parentheses for the type signature yields:
zipWith: ((a -> (b -> c)) -> ([a] -> ([b] -> [c])))
π Exercise: Understand parentheses when calling functions
A similar parenthesis blight has afflicted the site where we're calling our function. Add both the implied and necessary parentheses to the following code
use Nat
listA = [1,2,3,4,5]
listB = [2,4,6,8,10]
fixMe = List.zipWith a -> b -> a + b listA listB
The required parentheses are as follows:
use Nat
listA = [1,2,3,4,5]
listB = [2,4,6,8,10]
fixMe = List.zipWith (a -> b -> a + b) listA listB
Adding the implied parentheses for the order in which function application occurs:
use Nat
listA = [1,2,3,4,5]
listB = [2,4,6,8,10]
fixMe = ((List.zipWith (a -> b -> a + b) listA) listB)
π Exercise: Determine a type signature for a function from how it's called
Write the signature for List.foldLeft
given the following information:
An example of how foldLeft
is called is
You can read about what List.foldLeft
does by reading the docs linked here: List.foldLeft.doc
or by entering docs List.foldLeft
in the UCM.
Text.size
to transform Text
into a number, and then adds the length of each text element together, but jsonschema.lib.base.data.List.foldLeft
should be polymorphic--that is, it should not care if it is operating on is a List of Text, or a List of Char or a List of Boolean.The first argument to jsonschema.lib.base.data.List.foldLeft
is a function with two arguments, the first is the value that is being accumulated as the fold function is operating on each element on the list, the second corresponds to the element of the list.
The second argument to the jsonschema.lib.base.data.List.foldLeft
function is the value that should be applied when the higher order function encounters the end of the list.
The third argument to List.foldLeft is the list being folded over.
Note, the actual signature of List.foldLeft
contains a parameter in curly braces, {e}
. List.foldLeft
is ability polymorphic, meaning that the step function provided to it can perform effects. We'll be covering those later in our section on Abilities.
List.foldLeft : (b ->{π} a ->{π} b) -> b -> [a] ->{π} b
π Exercise: Debug a Unison function which fails to typecheck
brokenFactorial : Nat -> Nat
brokenFactorial n =
use Universal Nat
if n === 0 then 1 else n * brokenFactorial decrement n
We'll cover the use
keyword later, we're using it above to disambiguate a few function names.
Something is wrong with this function. It does not typecheck, and the UCM prints out the following error. See if you can fix it.
This looks like a function call, but with a Nat where the function should be. Are you missing an operator?
5 | if n === 0 then 1 else n * brokenFactorial decrement n
else
clause?Due to the order of function application, we need to surround the call to Nat.decrement
with parentheses.
use Nat *
factorial : Nat -> Nat
factorial n = if n === 0 then 1 else n * factorial (Nat.decrement n)
factorial 3⧨6
π Exercise: Write your own Unison function
Write a function which, when given a list, removes every other element from the list. So, ["a", "b", "c", "d"]
becomes ["a", "c"]
. The function should work on a list of any type.
removeEveryOther : [a] -> [a]
removeEveryOther as = base.todo "Implement here"
Some tests to validate this function are copied below, but they're also available under the ex5.tests
namespace.
test> test1 = check(removeEveryOther ["a","b","c","d","e"] test.=== ["a", "c", "e"])
test> test2 = check(removeEveryOther [1] test.=== [1])
test> test3 = check(removeEveryOther [] test.=== [])
jsonschema.lib.base.data.List.indexed
for a simple way to pair each element in the list with its index.Nat.mod
.One possible answer:
removeEveryOther : [a] -> [a]
removeEveryOther : [a] -> [a]
removeEveryOther ns =
iList = List.indexed ns
tups = List.filter (tup -> Nat.mod (at2 tup) 2 === 0) iList
List.map (tup -> at1 tup) tups