0

My Code

My piece of code, i.e.:

equal_suffix: Eq a => List a -> List a -> List a
equal_suffix u v with (snocList u)
    equal_suffix _ _ | Empty = []
    equal_suffix _ v | (Snoc x xs snx) with (snocList v)
        equal_suffix _ _ | (Snoc x xs snx) | Empty = []
        equal_suffix _ _ | (Snoc x xs snx) | (Snoc y ys sny) = case x == y of
            False => []
            True => (equal_suffix xs ys | snx | sny) ++ [x]

does not type check, with compile yelling:

Error: With clause does not match parent

Hello:857:25--857:38
 853 | 
 854 | equal_suffix: Eq a => List a -> List a -> List a
 855 | equal_suffix u v with (snocList u)
 856 |     equal_suffix _ _ | Empty = []
 857 |     equal_suffix _ v | (Snoc x xs snx) with (snocList v)
                               ^^^^^^^^^^^^^

My Question(s)

My first question is:

What does parent mean for a with clause in the context of Idris (Idris2 to be specific)? (Edit1: Thanks to @joel I now understand)

And if the first question can't help me understand this:

What is the problem with my code? (Edit1: Original Final Question)

What is the correct syntax of using nested with clause in Idris(2)? (Edit1: A More Focused Question thanks to the reminder from the comment @Vega)

(Excuse my snake-cased Pythonic mind for the naming of the variables :D)

Edit1 (2022-05-09): The question was closed because the original last question is not focused enough. I adjust my question hopefully to reopen this as I am still in trouble with the with clause still.

What I have tried

To add more details, I did try the @joel version myself independently, i.e., to only case-split after specifying all with statement:

func: input_type -> output_type
func input with (view1 input)
    func input | input_in_view1 with (view2 input)
        func input | input_in_view1 | input_in_view2 = ...

I also tried to make a tuple of the two views, i.e.,

func: input_type -> output_type
func input with (view1 input, view2 input)
    func input | (input_in_view1, input_in_view2) = ...

However, these two do not seem to work (the first leads to an unsolved hole error and the second non-covering error or non terminating type checking depending on how I case-split) .

Example from TDD by Edwin

This equal_suffix exercise is from TDD by Edwin. I was still stuck and stopped at exactly this exercise.

Here is an example in the book which I copy as follows:

isSuffix : Eq a => List a -> List a -> Bool
isSuffix input1 input2 with (snocList input1)
    isSuffix [] input2 | Empty = True
    isSuffix (xs ++ [x]) input2 | (Snoc rec) with (snocList input2)
        isSuffix (xs ++ [x]) [] | (Snoc rec) | Empty = False
        isSuffix (xs ++ [x]) (ys ++ [y]) | (Snoc rec) | (Snoc z) 
            = if x == y then isSuffix xs ys | xsrec | ysrec
                else False

where snocList is redefined in the book for educational purpose and rec might be just a typo of xsrec and ysrec respectively.

Recursing on with clause directly for the totality.

I did manage to make it work when changing the recursive call equal_suffix xs ys | snx | sny to equal_suffix xs ys

However, according to the book P275, to make a totally defined function, we need to recurse on the with clause directly to tell compiler about the relation between the recursive calls, so I want the function to be defined by directly calling the with clause recursively.

Clément Dato
  • 283
  • 2
  • 7
  • SO question post should have one question at the time – Vega May 07 '22 at 14:45
  • @Vega one qu is a half-way point to fully answering the other. Seems reasonable to me – joel May 07 '22 at 14:51
  • @Joel, _what is the problem with my code_ alone is enough reason to close for not being focused. You have enough rep to close vote – Vega May 07 '22 at 14:53
  • you can check it's total by putting `total` in front of the definition. In this case, `| sny` does _not_ appear to be necessary for totality – joel May 09 '22 at 11:01
  • also note `isSuffix` from the book is for Idris 1 not Idris 2. The `rec` argument to `Snoc`, which iirc is only in Idris2, may be removing the need for `| sny` – joel May 09 '22 at 11:05
  • having a look at the [updates required](https://idris2.readthedocs.io/en/latest/typedd/typedd.html#chapter-10) for the book in Idris 2, `isSuffix` looks like a bad example "The recursive with application in Idris 1 probably shouldn’t have allowed this" – joel May 09 '22 at 11:11

1 Answers1

1

Simplest fix: remove | sny in your final line. Apparently it's not needed.

"Parent" presumably means parent function call in the recursive loop.

Now as to why it doesn't compile with | sny ... my guess is your second view is only present in one branch of your pattern match, whereas it needs to be present in both if you're going to pass sny recursively in equal_suffix xs ys | snx | sny.

You might be able to get something like this to work

equal_suffix: Eq a => List a -> List a -> List a
equal_suffix u v with (snocList u)
  equal_suffix u v | su with (snocList v)
    equal_suffix [] _ | Empty | _ = []
    equal_suffix _ [] | _ | Empty = []
    equal_suffix (xs ++ [x]) (ys ++ [y]) | (Snoc x xs snx) | (Snoc y ys sny) =
      case x == y of
        False => []
        True => (equal_suffix xs ys | snx | sny) ++ [x]

but this particular example fails to compile with unsolved holes.

joel
  • 6,359
  • 2
  • 30
  • 55
  • "Parent" in this error message refers to the definition above the currently-matched `with`. So `(Snoc x xs snx)` apparently doesn't match the preceding `with` clause. – shadowtalker May 09 '22 at 03:55
  • Thank you very much for your answer :D. I tried to do this but get also the unsolved holes. I don't understand where the unsolved holes are (which I understand as an implicit argument that cannot be resolved by the compiler, but I don't see where it is). – Clément Dato May 09 '22 at 07:11