Purescript Book - Questions

Even though this was probably not your intent, showing how to apply the remaining argument might clarify things. For example, you could put your Array Int into a NonEmpty collection of another Array of arrays or a List of arrays. This parent collection is what that t1 type variable in the error message represents.

> a = NonEmpty [1, 2]

> b = a [[3, 4], [5, 6]]
> b
(NonEmpty [1,2] [[3,4],[5,6]])

> :t b
NonEmpty Array (Array Int)

> c = a ([3, 4] : [5, 6] : Nil)
> c
(NonEmpty [1,2] ([3,4] : [5,6] : Nil))

> :t c
NonEmpty List (Array Int)

The NonEmpty syntax tripped me up too when going through the book, so I figured it’s about time to add some more beginner-friendly examples to the docs (PR). Looking forward to when these can be replaced with doctest.

Also, I’ll add a note in the book that show should produce what you’d need to paste into the repl to create the value being shown. (Edit: PR)

2 Likes

Fantastic, thanks both! :slight_smile:

I am stuck again, trying to implement Semigroup

So I tried

instance semiGroupNonEmpty :: Semigroup (NonEmpty a) where
    append (NonEmpty x xs) (NonEmpty y ys) = 
        (append (NonEmpty x) (NonEmpty y)) (append xs ys)

In the repl

--
> import Exercises        
> b = NonEmpty 2 [1, 2]
> a = NonEmpty 1 [1, 2]
> append a b           
C:\projects\purescriptbook\ch6\.psci_modules\node_modules\Data.Semigroup\foreign.js:13
    return xs.concat(ys);
              ^

RangeError: Invalid array length

Then I tried the same operation with the source module, why is this giving an error?

> import Data.NonEmpty
> a = NonEmpty 1 [1, 2]
> b = NonEmpty 2 [1, 2]
> append a b
Error found:
in module $PSCI
at :1:1 - 1:9 (line 1, column 1 - line 1, column 9)

  No type class instance was found for
  
    Data.Semigroup.Semigroup (NonEmpty Array Int)
  

while applying a function append
  of type Semigroup t0 => t0 -> t0 -> t0
  to argument a
while inferring the type of append a
in value declaration it

where t0 is an unknown type

Then if I try

instance semiGroupNonEmpty :: Semigroup (NonEmpty a) where
    append (NonEmpty x xs) (NonEmpty y ys) = 
        NonEmpty x (append xs (append [y] ys))

In the repl

> x = NonEmpty 1 [ 2, 3 ]
> y = NonEmpty 4 [ 5, 6 ]
> append x y
(NonEmpty 1 [2,3,4,5,6])

I have a bit of a hard time grasping this… In my head If I append NonEmpty 1 [ 2, 3 ] to NonEmpty 4 [ 5, 6 ] I should get something like NonEmpty [1, 4] [[2,3], [5, 6]] …as @milesfrain has done with the a, b example above? So I would end up with an array type and array of arrays?

Not quite. The unit tests should help answer this question.


You should enable those to check your work as you solve each exercise.

Looks like the latter solution you wrote is correct.

A good way to think about NonEmpty is that it should behave like an array (or other collection) that’s guaranteed to have at least one element (represented by that first element displayed outside of the collection). Appending two 1D arrays should still result in a 1D array.

1 Like

When you write this:

(append (NonEmpty x) (NonEmpty y))

you’re actually making use of the semigroup instance for functions, which is defined like this:

instance semigroupFn :: Semigroup s' => Semigroup (s -> s') where
  append f g x = f x <> g x

so what you end up with is:

append (NonEmpty x) (NonEmpty y)
= \a -> NonEmpty x a <> NonEmpty y a

Therefore, when you write append (NonEmpty 1 [1,2]) (NonEmpty 2 [1,2]) it evaluates as:

append (NonEmpty 1 [1,2]) (NonEmpty 2 [1,2])
= (\a -> NonEmpty 1 a <> NonEmpty 2 a) (append [1,2] [1,2])
= (\a -> NonEmpty 1 a <> NonEmpty 2 a) [1,2,1,2]
= NonEmpty 1 [1,2,1,2] <> NonEmpty 2 [1,2,1,2]

I think the error you’re seeing is arising from the fact that eventually the array becomes so large that your JS VM is refusing to concatenate them.

1 Like