0

I am trying to append function that works on Nested Lists like regular lists. I want to use Either String (Nested a) so that it returns error or the appended list. But it keeps failing. I am not doing NestedList[NestedList a] anywhere. Why does it say it expected [NestedList (NestedList a)]

module Main where

data NestedList a=Elem a | List[NestedList a] deriving Show

flatten ::NestedList a->[a]
flatten (Elem x)=[x]
flatten (List(x:xs))=flatten(x)++flatten(List xs)
--flatten NestedList (x:xs)=flatten(x)++flatten(xs)
flatten(List [])=[]

------------------

count::[a]->Int
count a=length (a)

-----------------
append::NestedList a->NestedList a->Either String (NestedList a)
append (_) (Elem a)=Left "Elements are not allowed"
append (Elem a) (_)=Left "Elements are not allowed"
append (List a) (List b)=Right (List (flatten(List a)++flatten(List b)))
-------------------

main=do
        print(flatten (List[Elem 1, Elem 2,List[Elem 1, Elem 2 ]]))
        print(count(flatten (List[Elem 1, Elem 2,List[Elem 1, Elem 2 ]])))
        print(append (List[List[Elem 1, Elem 2 ]]) (List[Elem 1, Elem 2,List[Elem 1, Elem 2 ]]    ))  

gives me this error

   flatten_list.hs:18:52:
   Couldn't match type `a' with `NestedList a'
      `a' is a rigid type variable bound by
      the type signature for
        append :: NestedList a
                  -> NestedList a -> Either String (NestedList a)
      at flatten_list.hs:15:9
       Expected type: [NestedList (NestedList a)]
  Actual type: [NestedList a]
In the first argument of `List', namely `a'
In the first argument of `flatten', namely `(List a)'
In the first argument of `(++)', namely `flatten (List a)'

flatten_list.hs:18:69:
    Couldn't match type `a' with `NestedList a'
  `a' is a rigid type variable bound by
      the type signature for
        append :: NestedList a
                  -> NestedList a -> Either String (NestedList a)
      at flatten_list.hs:15:9
    Expected type: [NestedList (NestedList a)]
  Actual type: [NestedList a]
In the first argument of `List', namely `b'
In the first argument of `flatten', namely `(List b)'
In the second argument of `(++)', namely `flatten (List b)'
Stephen Diehl
  • 8,271
  • 5
  • 38
  • 56
  • The problem is that the `List` data constructor takes an argument of type `[NestedList a]` but in the line `Right (List (flatten(List a)++flatten(List b)))`, you are providing it with a value of type `[a]` (i.e., the result of `flatten(List a)++flatten(List b)`). This is why it tries to infer the type `[NestedList (NestedList a)]`. – David Young Jan 17 '14 at 02:49

1 Answers1

1
import Data.Traversable

append :: NestedList a -> NestedList a -> Either String (NestedList a)
append (Elem x) (Elem y) = Right $ List [Elem x, Elem y] 
append (Elem _) _ = Left ""
append _ (Elem _) = Left "" 
append (List xs) (List ys) = fmap List $ sequenceA $ zipWith append xs ys 

The append you wrote in your questions seems to want to just flatten and concatenate the two lists, which is rather pointless, since you are throwing away all the structure. If this is desired behavior, then just use a regular list:

append' :: NestedList a -> NestedList a -> Either String [a]
append' (Elem x) (Elem y) = Right $ [x,y]
append' (Elem _) _ = Left ""
append' _ (Elem _) = Left "" 
append' a b        = Right $ flatten a ++ flatten b

You could also define your datatype in terms of the free monad:

import Control.Monad.Free
type NestedList = Free []

flatten :: NestedList a -> [a]
flatten = retract 

append :: NestedList a -> NestedList a -> Either String (NestedList a)
append (Pure x) (Pure y) = Right $ Free [Pure x, Pure y] 
append (Pure _) _ = Left ""
append _ (Pure _) = Left "" 
append (Free xs) (Free ys) = fmap Free $ sequenceA $ zipWith append xs ys 

This definition is isomorphic to the one you gave.

user2407038
  • 14,400
  • 3
  • 29
  • 42
  • I tried where it does append (List xs) (List ys) = fmap List $ sequenceA $ zipWith append xs ys \n\n\n.Not sure why I got "Elements are not allowed" for this call print(append (List[List[Elem 1, Elem 2 ]]) (List[Elem 1, Elem 2,List[Elem 1, Elem 2 ]])) ? I wanted to print "Elements not allowed" if any of the lists is not a list but an element, which I thought append (_) (Elem a)=Left "Elements are not allowed" append (Elem a) (_)=Left "Elements are not allowed" were doing and there is no recursion in append (List xs) (List ys) = fmap List $ sequenceA $ zipWith append xs ys . –  Jan 17 '14 at 04:54
  • But there is recursion in `append`. The call to `zipWith` calls `append`, so `append` calls itself. This means it will always reduce down to an `Elem` (I believe) and append will always give a `Left`. – David Young Jan 17 '14 at 05:10
  • Well there is recursion but I need to check the lists in the beginning but there can and will be elements inside the list :( –  Jan 17 '14 at 05:11
  • You could make another function that checks the list in the beginning, and then if it isn't an `Elem` call `append`. – David Young Jan 17 '14 at 05:12
  • `---------------- checkappend::NestedList a->NestedList a->Either String (NestedList a) checkappend (List _) (Elem _)=Left "Elements are not allowed" checkappend (Elem _) (List _)=Left "Elements are not allowed" checkappend (Elem _) (Elem _)=Left "elements are not allowed" checkappend (List a) (List b)= append a b ---------------- append::NestedList a->NestedList a->NestedList a append (List a) (List b)= fmap List $ sequenceA $ zipWith append a b -------------------` –  Jan 17 '14 at 05:21
  • ERROR:Couldn't match type `a' with `NestedList a0' `a' is a rigid type variable bound by the type signature for append :: NestedList a -> NestedList a -> NestedList a at flatten_list.hs:22:9 Expected type: NestedList [NestedList a0] Actual type: NestedList [a] In the second argument of `($)', namely `sequenceA $ zipWith append a b' In the expression: fmap List $ sequenceA $ zipWith append a b In an equation for `append': append (List a) (List b) = fmap List $ sequenceA $ zipWith append a b –  Jan 17 '14 at 05:23
  • @PreetiGupta Actually, how do you want the appending to work? What about this? `append (List a) (List b) = List (a ++ b)` – David Young Jan 17 '14 at 06:11
  • doing `append (List a) (List b) = List (a ++ b)` will loose all the nested structure –  Jan 17 '14 at 06:13
  • I forgot the base case of the recursion (two `Elem`s). If at least one of the base cases is not `Right`, the function will always return `Left`. The current version returns `Right` if the two input lists have the same amount of nesting, `Left` otherwise. – user2407038 Jan 17 '14 at 07:23
  • don't both the lists in print(append (List[List[Elem 1, Elem 2 ]]) (List[Elem 1, Elem 2,List[Elem 1, Elem 2 ]])) have same level of nesting? Both the lists [[1,2]] and [1,2[1,2]] have two level of nesting but it still returns left. –  Jan 17 '14 at 18:27
  • Those two input lists don't have the same structure, since the first element of the first list is `List` and the first element of the 2nd list is `Elem`, so this should fail. You can still concatenate them, but your code made it seem like you want this case to be a failure case. – user2407038 Jan 18 '14 at 02:34