Home > other >  How to solve this in Haskell?
How to solve this in Haskell?

Time:10-25

I'm a beginner in Haskell and I would need help with this problem.

e :: [[(c,[d])]] -> Int 
e [(x,xs):[y,ys]] = 0

The goal would be to define a term "z", that gives "e z == 0". I just can't figure it out, any help would be appreciated.

CodePudding user response:

Well, you have a clause right before you that will give 0 as the result, so all that's left to do is to generate a term matching it. Because patterns and expressions use essentially the same syntax, that's just a matter of taking the pattern

   [(x,xs):[y,ys]]

and replacing all the variables with concrete values. In this case there's an extremely easy solution: note that the matched variables aren't even used, i.e. the clause could (and should!) have been written like this (I'm also regrouping to make the list syntax more consistent)

e [[(_,_),_,_]] = 0

Because of this, you could simply leave them all undefined:

Prelude> let e :: [[(c,[d])]] -> Int ; e [[(_,_),_,_]] = 0
Prelude> e [[(undefined, undefined), undefined, undefined]]
0

If you want something that feels less like a cheat, you need to pick concrete types for c and d. You can do that at will because they're unconstrained polymorphic type-variables; let's use c ~ Char and d ~ Bool. The most elegant way of picking concrete types is to use the type-applications extension

Prelude> :set -XTypeApplications
Prelude> :t e @Char @Bool
e @Char @Bool :: [[(Char, [Bool])]] -> Int

Then, you can ask the compiler what type each gap should be.

Prelude> e @Char @Bool [[(_,_),_,_]]

<interactive>:6:36: error:
    • Found hole: _ :: CharIn the expression: _
      In the expression: (_, _)
      In the expression: [(_, _), _, _]
    • Relevant bindings include it :: Int (bound at <interactive>:6:1)

...

ok, let's put in some random character, how about 'q'

Prelude> e @Char @Bool  [[('q',_),_,_]]

<interactive>:7:40: error:
    • Found hole: _ :: [Bool]
    • In the expression: _
      In the expression: ('q', _)
      In the expression: [('q', _), _, _]
    • Relevant bindings include it :: Int (bound at <interactive>:7:1)

...

list of booleans, let's pick [True],

Prelude> e @Char @Bool  [[('q',[True]),_,_]]

<interactive>:9:48: error:
    • Found hole: _ :: (Char, [Bool])
    ...

and so on.

CodePudding user response:

I have changed the function signature to make it possible to return x for showing purposes but the pattern is the same:

e :: Num a => [[(a,[a])]] -> a
e [(x,xs):[y,ys]] = x

The following term will match and return x which is zero.

λ> e [[(0, [1,2]), (3, [4,5]), (6, [7, 8])]]
0

Please note that the patterns are non-exhaustive meaning that if you give e anything with a different structure (not value), will result in an exception.

This pattern [(x,xs):[y,ys]] effectively means that you need to pass a list that has exactly 3 elements. If you look at this (x,xs):[y,ys], you see that it's a list of two elements with one to their left. That element to the left in turn is a tuple which is also destructured into its members and when you set the first member to zero, it return zero.

Alternatively, if you like to generally match on the given pattern and don't care to extract any elements, which was your original question, it becomes easier:

e' :: [[(c,[d])]] -> Int 
e' [(x,xs):[y,ys]] = 0

Just pass in a list inside a list that has exactly 3 elements which are tuples as follows:

λ> e' [[(1,[]), (1,[]), (1,[])]]
0
  • Related