[Haskell-cafe] list -> sublists

Richard O'Keefe ok at cs.otago.ac.nz
Tue Oct 20 20:08:19 EDT 2009


On Oct 21, 2009, at 3:16 AM, satorisanitarium wrote:

>
> I just started learning haskell and I just came to my first wtf  
> moment.
>
> I'm trying to do something like this:
>
> calling:
> foo 3 [1,2,3,2,4,1,6,3,6,2,3,5,2,5,2,1,6,4]
>
> returns:
> [[1,2,3],[2,4,1,6,3],[2,3]]
>
> but i have no idea how to put something into a sublist.

 From the way you talk about the problem, I suspect that you are
trying to understand in a rather complicated way.

Here's how I approach your example:
     foo item list =
         if there is an occurrence of item in list then
            a new list whose first element is everything up to and  
including
            that occurrence
            and whose remaining elements are found by applying foo  
item to
            everything after that occurrence
         else
            an empty list

We can do this in just a couple of lines using List.elemIndex and  
splitAt,
but let's do it in an elementary way.  We'll write a helper function  
that
either returns (before-and-including-item, after-item) or nothing.

     find_and_split :: Eq t => t -> [t] -> Maybe ([t], [t])

     find_and_split item list = loop list []
       where loop [] _ = Nothing
             loop (x:xs) before | x == item = Just (reverse  
(x:before), xs)
             loop (x:xs) before             = loop xs (x:before)

     foo :: Eq t => t -> [t] -> [[t]]

     foo item list =
       case find_and_split item list of
         Nothing              -> []
         Just (before, after) -> before : foo item after

The answer I get is
*Main> foo 3 [1,2,3,2,4,1,6,3,6,2,3,5,2,5,2,1,6,4]
[[1,2,3],[2,4,1,6,3],[6,2,3]]
                       ^
which differs from yours at the marked place, but which I think is  
right.

List.elemIndex tells you where an element occurs.
Just 0 is the first position.
splitAt splits a list into two pieces, the size argument tells you
the length of the first piece.  So

     foo item list =
       case List.elemIndex item list of
         Nothing  -> []
         Just pos -> before : foo item after
                     where (before, after) = splitAt (pos+1) list

This gives the same answer as the previous version.

In neither case do we do ANYTHING to "put" items into a "sublist",
we just construct a list whose elements happen to be lists.  It's
no different from calculating a list of numbers.



More information about the Haskell-Cafe mailing list