Write a function,`stubs.Guess.score`

,with the following signature:

`stubs.Guess.score : stubs.Guess -> stubs.Target -> [stubs.Result]`

Given a 5 letter target and a 5 letter user guess, it should return the guess with each character annotated as one of the following:

- in the correct place
- in the target word but not in the correct place
- not in the target word

We've given this function a signature which suggests we've created our own data types for this step. The data constructors for these types currently contain a placeholder type,`TODO`

,which you can replace with what you think the type should enclose.

In Unison it's common to provide functions called`fromText`

or`toMyType`

which create values of a given type, for example`lib.base.Text.toBag`

or`Nat.toInt`

.We should have those for our Wordle guess and target types too!

Choose your data representations wisely!

**How to define a function**

**How to define a function**

See how to write a simple Unison function together:

**How search for functions by type and with wildcards**

**How search for functions by type and with wildcards**

If you ever find yourself wondering "π€ What's the Unison name for that function which turns a List into a Set?" or "π§ How do I break apart Text into its constituent characters?" you may want to use the type-based`find`

command.

When you want to search by type, the`find`

command is followed by a colon`:`

and then a type signature.

```
.> find : List a -> Set a
1. .base.Set.fromList : [k] -> Set k
```

```
.> find : Text -> [Char]
1. .base.Text.toCharList : Text -> [Char]
```

You might also try employing wildcard operators to help scope your search further. Say I wanted to find all the functions under the`List`

namespace in`base`

.If I type`find List`

in the UCM, I'll receive a bunch of results that include the word`List`

in their name, but aren't scoped to the namespace. Instead, we can use`?`

to represent any results following the given prefix.

```
.> find .base.List.?
1. structural type .base.List.Nonempty a
2. .base.List.++ : [a] -> [a] -> [a]
3. .base.List.+: : a -> [a] -> [a]
4. .base.List.:+ : [a] -> a -> [a]
[...]
```

```
.> find .base.List.delete?
1. .base.List.deleteAt : Nat -> [a] -> [a]
2. .base.List.deleteAt.doc : Doc.Deprecated
3. .base.List.deleteAt.test : [Test.Result]
4. .base.List.deleteFirst : (a ->{g} Boolean) -> [a] ->{g} [a]
[...]
```

**Data type definition suggestions**

**Data type definition suggestions**

The user and target word will initially be entered as type`Text`

values, but dealing with the raw`Text`

values might not be optimal for making the kinds of comparisons needed to produce a result.

Why not create three types that contain variouscollection typesand types from`base`

to model this domain?

- A
`Target`

data type which contains enough information to check for the existence of a`Char`

in the target, and the location (an index perhaps? π) of a character in the target. - A
`Guess`

data type which contains information about the guessed word's characters and their locations. - A
`Result`

data type which represents the result of comparing a `type Char` from the`Guess`

with the`Target`

.

## Resources

## Solutions

**An implementation walk through**

**An implementation walk through**

One possible way to model the domain:

`type basic.Guess`

```
type basic.Guess
= labs.wordle.solutions.basic.Guess.Guess [(Char, Nat)]
```

`type basic.Result`

Let's look how we might transform a raw text value into our respective`basic.Guess`

and`basic.Target`

types.

First, we'll write a`Text.normalize`

function to lowercase and strip whitespace from the incoming text. We don't want the`basic.Guess`

to fail to match the`basic.Target`

because of casing or whitespace issues.

`Text.normalize : Text -> Text`

```
Text.normalize : Text -> Text
Text.normalize input =
trim input
|> toCharList
|> lib.base.data.List.map ascii.toLower
|> fromCharList
```

Then we break down the`Text`

body into a`List`

of`Char`

with the`toCharList`

function from`base.`

Working in the`List`

type allows us to call`lib.base.data.List.indexed`

so we can pair the character with its index for position lookup later.

```
basic.Guess.fromText : Text -> basic.Guess
basic.Guess.fromText input =
normalized = Text.normalize input
charList = toCharList normalized |> lib.base.data.List.indexed
basic.Guess.Guess charList
```

We do the same sequence of transformations for the`basic.Target`

type, with the additional step of calling`lib.base.data.Set.fromList`

to create two`Set`

sβonewhich includes the indices of the characters, and one without.

```
basic.Target.fromText : Text -> basic.Target
basic.Target.fromText input =
use lib.base.data.Set fromList
normalized = Text.normalize input
charList = toCharList normalized
charsWithIndex = charList |> lib.base.data.List.indexed |> fromList
setChars = fromList charList
basic.Target.Target setChars charsWithIndex
```

Next we'll break down the overall`basic.Guess.score`

function implementation.

`basic.Guess.score : basic.Guess -> basic.Target -> [basic.Result]`

```
basic.Guess.score : basic.Guess -> basic.Target -> [basic.Result]
basic.Guess.score guess target =
(basic.Guess.Guess list) = guess
lib.base.data.List.map (t -> basic.characterResult t target) list
```

For each character and index tuple in the user's`basic.Guess`

,we call the`basic.characterResult`

function. It checks whether the tuple is`basic.inLocation`

,or if it merely`basic.exists`

in the target.

`basic.characterResult : (Char, Nat) -> basic.Target -> basic.Result`

```
basic.characterResult : (Char, Nat) -> basic.Target -> basic.Result
basic.characterResult tuple target = match tuple with
tup
| basic.inLocation tup target -> basic.Result.InPlace (at1 tup)
| basic.exists tup target -> basic.Result.Exists (at1 tup)
| otherwise -> basic.Result.NotFound (at1 tup)
```

The two boolean functions`basic.inLocation`

and`basic.exists`

both use`Set.contains`

in their implementations.

`basic.inLocation : (Char, Nat) -> basic.Target -> Boolean`

```
basic.inLocation : (Char, Nat) -> basic.Target -> Boolean
basic.inLocation tup = cases
basic.Target.Target _ indexedChars -> Set.contains tup indexedChars
```

`basic.exists : (Char, Nat) -> basic.Target -> Boolean`

```
basic.exists : (Char, Nat) -> basic.Target -> Boolean
basic.exists tup target =
(char, index) = tup
(basic.Target.Target set _) = target
Set.contains char set
```