Home > Blockchain >  how to return inputted value when no value is found in list comprehension Haskell
how to return inputted value when no value is found in list comprehension Haskell

Time:10-07

I'm trying to create a function which finds the pair of a character inputted, in a list, that is also inputted.

findc :: Char -> [(Char, Char)] -> Char
findc x list = head[ if null c then x else c| (n,c) <- list, x == n ]

if no letter is found in list that matches input, the function is meant to return the value inputted. The above code doesn't work as null is invalid type for c.
the following code only works for when a letter is found:

findc :: Char -> [(Char, Char)] -> Char
findc x list = head[ c| (n,c) <- list, if x == n then c==c else c==x]
 > findc 'B' [('A','F'), ('B','G'), ('C','H')]
'G'

but when not found it doesn't work, as it returns empty list rather than the inputted char.

How can i return the inputted char if char not found in list?

CodePudding user response:

There is already a function in Prelude that does most of what you want:

lookup :: Eq a => a -> [(a, b)] -> Maybe b

With this, all you have to do is call lookup and then distinguish the Just and Nothing cases:

findc :: Eq a => a -> [(a, a)] -> a
findc goal table = case lookup goal table of
  Nothing -> goal
  Just subst -> subst

But of course there is also a function for unwrapping a Maybe with a default value:

fromMaybe :: a -> Maybe a -> a

Combining these two, we get a simple definition:

findc :: Eq a => a -> [(a, a)] -> a
findc goal table = fromMaybe goal (lookup goal table)

If you are so inclined, you can play some code golf here, by noting that the table argument is just sorta handed from findc into its implementation at the end, which you can make implicit:

findc :: Eq a => a -> [(a, a)] -> a
findc goal = fromMaybe goal . lookup goal

Finally, the truly maniacal might try to eliminate the goal argument, which is an interesting exercise, but does not yield a very readable result:

findc :: Eq a => a -> [(a, a)] -> a
findc = liftA2 (.) fromMaybe lookup

CodePudding user response:

Your first code contains the right kind of ideas but in a wrong order. You can put the if expression outside of the comprehension:

findc :: Char -> [(Char, Char)] -> Char
findc x list = 
  let filtered = [ c | (n,c) <- list, x == n ]
  in if null filtered then x else head filtered

But it is more idiomatic to use pattern matching instead of an if expression and null and head:

findc :: Char -> [(Char, Char)] -> Char
findc x list = 
  case [ c | (n,c) <- list, x == n ] of
    [] -> x
    (y:_) -> y

CodePudding user response:

Rather than using a list comprehension, you could use Data.List.find. This function returns a Maybe type, which you can pattern match on to either return the character provided, or the corresponding character from the list of tuples.

import Data.List

findc :: Char -> [(Char, Char)] -> Char
findc ch lst =
  let match = find ((ch ==) . fst) lst
  in
    case match of
      Nothing -> ch
      Just (_, v) -> v 

CodePudding user response:

This is another way of doing this:

 data Result a = Found a | NotFound a deriving Show

 lst = [('A','F'), ('B','G'), ('C','H')]

 findc :: Char -> [(Char, Char)] -> Result Char
 findc x [] = NotFound x
 findc x (n:ns)
    | x == fst n = Found (snd n)
    | otherwise = findc x ns

 main = do
    print $ findc 'B' lst    -- Found 'G'
    print $ findc 'D' lst    -- NotFound 'D'

I created a new data structure for the result, either Found value or NotFound value. This prevents the problem where we have a list including ('B','B'), which returns the search term even though the search term has successfully matched.

  • Related