Question

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)'
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top