Search code examples
haskellparse-error

Parse error in pattern in my little program


left :: [String]->[Char]->Char
left [] _ = []
left (x:xs) (head xs) = x    -- it says error at head

I used proper parenthesis but still taking parse error.By the way, I m trying to get previous element in list such as [["A"],["B"],["C"],["D"],["E"]] . Maybe I have some other mistakes. Pls correct me .

2nd question is how can pick previous elements previous indexed character. Such as giving function this list [["J","O","H","N"],["A","L","I","C","E"]] and "C" , I want to expect to get "H". I mean "C" is 2nd element 4th index and "H" is previous elements 3rd index. Thnx in advance


Solution

  • If I understood you well, you need a function which find a character in a list of String, and return the character of the preceding string at the preceding index.

    Something like:

    f ["JOHN", "ALICE"] 'C' == 'H'
    

    First you need to know that Char literals are delimited with simple quotes in Haskell ('A'), and String literals with double quotes ("ABC").

    Since in Haskell String is an alias for [Char], "ABC" is equivalent to ['A', 'B', 'C'].

    This said, in Haskell you can't define a function like this: f a a = stuff. GHC will complain that a is defined multiple times. So to check if two arguments have some property, you need guard patterns.

    So I would write your first function like this:

    left :: [String] -> String -> String
    left [] _ = ""
    left [x] _ = ""
    left (x1:x2:xs) str
        | x2 == str = x1
        | otherwise = left (x2:xs) str
    

    For your second question:

    import Data.List
    
    f :: [String] -> Char -> Maybe Char
    f [] _ = Nothing
    f [a] _ = Nothing
    f (x1:x2:xs) c
        | Just i <- elemIndex c x2 = Just $ x1 !! (i-1)
        | otherwise = f (x2:xs) c
    

    Notes:

    • left should also return a Maybe String in case str isn't found or is first.
    • f doesn't check if x1 is actually long enough
    • Usually in Haskell, the list parameter is last, to permit currying.

    EDIT:

    A somewhat more clever approach with zip (in module Data.List).

    f :: [String] -> Char -> Maybe Char
    f [] _ = Nothing
    f [_] _ = Nothing
    f (x1:"":xs) c = f xs c
    f (x1:x2:xs) c = f' (zip x1 (tail x2))
        where f' [] = f (x2:xs) c
              f' ((a,b):l) = if b == c then a else f' l
    

    This version won't crash. It will return the first character which satisfies "being mth character in nth string, while the (m+1)th character in (n+1)th string" is c. The result will be wrapped in a Maybe (Just 'H'). Otherwise, it returns Nothing (Maybe is roughly the nullable type for Haskell).

    zip is a function which merges two lists in one list of pairs:

    zip ['a', 'b', 'c'] [1, 2] == [('a', 1), ('b', 2)]
    

    The size of the resulting list is the one of the smallest. So in the example, what happens is:

    zip "JOHN" (tail "ALICE") == [('J','L'), ('O', 'I'), ('H', 'C'), ('N', 'E')]
    

    You then just have to check is the second character is the searched one, and then return the first character of the pair.