Mathis Panzani
Mathis Panzani

Reputation: 85

Haskell- Is string only composed of characters from another string

I want to check if a string given by the user is only composed from characters of another string previously given as program arguments

I have search every where for doing this in haskell but I didn't found anything (found answer for other language but not haskell) I know how to do this in python or in C but this is my first haskell program

Here is what I have so far :

I'm calling the function + setup of the string to check

myCheck first second = do
-- some stuff
let alpha = "01" -- normally this is given with argument by the user but just for simplicity let's do it that way (it could also be alpha = "aziuefè!çè")
suite <- getLine
if isValid suite alpha
  then putStr "OK\n"
  else exit
-- some other stuff

Now the Is valid function the isValid "" alpha = True is important because I need to handle that elsewhere later in the code

isValid :: String -> String -> Bool                                                                       
isValid "" alpha = True                                                                                   
isValid xs alpha =                                                                                      
  case dropWhile (isAlphabet xs alpha) of                                                                  
    "" -> True                                                                                             
   ('.':ys) -> all (isAlphabet ys alpha)                                                                  
   _ -> False

And the isAlphabet function

isAlphabet :: Char -> String -> Bool                                                                     
isAlphabet xs alpha = xs `elem` alpha

But (and I'm starting to get used to while using haskell)

 /Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:29:19: error:
• Couldn't match expected type ‘a0 -> Bool’ with actual type ‘Bool’
• Possible cause: ‘isAlphabet’ is applied to too many arguments
  In the first argument of ‘dropWhile’, namely
    ‘(isAlphabet xs alpha)’
  In the expression: dropWhile (isAlphabet xs alpha)
  In the expression:
    case dropWhile (isAlphabet xs alpha) of
      "" -> True
      ('.' : ys) -> all (isAlphabet ys alpha)
      _ -> False
     |
  29 |   case dropWhile (isAlphabet xs alpha) of
     |                   ^^^^^^^^^^^^^^^^^^^
/Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:29:30: error:
• Couldn't match type ‘[Char]’ with ‘Char’
  Expected type: Char
    Actual type: String
• In the first argument of ‘isAlphabet’, namely ‘xs’
  In the first argument of ‘dropWhile’, namely
    ‘(isAlphabet xs alpha)’
  In the expression: dropWhile (isAlphabet xs alpha)
   |
29 |   case dropWhile (isAlphabet xs alpha) of
   |                              ^^

/Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:30:5: error:
    • Couldn't match expected type ‘[a0] -> [a0]’
              with actual type ‘[Char]’
    • In the pattern: ""
     In a case alternative: "" -> True
     In the expression:
    case dropWhile (isAlphabet xs alpha) of
      "" -> True
      ('.' : ys) -> all (isAlphabet ys alpha)
      _ -> False
   |
30 |     "" -> True
   |     ^^

/Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:31:6: error:
 • Couldn't match expected type ‘[a0] -> [a0]’
               with actual type ‘[Char]’
 • In the pattern: '.' : ys
  In a case alternative: ('.' : ys) -> all (isAlphabet ys alpha)
  In the expression:
    case dropWhile (isAlphabet xs alpha) of
      "" -> True
      ('.' : ys) -> all (isAlphabet ys alpha)
      _ -> False
   |
31 |     ('.':ys) -> all (isAlphabet ys alpha)
   |      ^^^^^^

/Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:31:17: error:
  • Couldn't match expected type ‘Bool’
              with actual type ‘t0 a1 -> Bool’
  • Probable cause: ‘all’ is applied to too few arguments
  In the expression: all (isAlphabet ys alpha)
  In a case alternative: ('.' : ys) -> all (isAlphabet ys alpha)
  In the expression:
    case dropWhile (isAlphabet xs alpha) of
      "" -> True
      ('.' : ys) -> all (isAlphabet ys alpha)
      _ -> False
   |
31 |     ('.':ys) -> all (isAlphabet ys alpha)
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^

/Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:31:22: error:
   • Couldn't match expected type ‘a1 -> Bool’ with actual type ‘Bool’
   • Possible cause: ‘isAlphabet’ is applied to too many arguments
    In the first argument of ‘all’, namely ‘(isAlphabet ys alpha)’
    In the expression: all (isAlphabet ys alpha)
    In a case alternative: ('.' : ys) -> all (isAlphabet ys alpha)
   |
31 |     ('.':ys) -> all (isAlphabet ys alpha)
   |                      ^^^^^^^^^^^^^^^^^^^

/Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:31:33: error:
  • Couldn't match expected type ‘Char’ with actual type ‘[Char]’
  • In the first argument of ‘isAlphabet’, namely ‘ys’
    In the first argument of ‘all’, namely ‘(isAlphabet ys alpha)’
    In the expression: all (isAlphabet ys alpha)
   |
31 |     ('.':ys) -> all (isAlphabet ys alpha)
   |                                 ^^

This specific function isn't homework but part of a bigger project that is Thank you, really hope I didn't miss any previous questions already answered

Edit suggested by answer :

Removed isAlphabet (this function wasn't making any sense, since it was only calling elem)

isValid :: String -> String -> Bool                                                                    
isValid "" alpha = True                                                                              
isValid xs alpha =                                                                                         
  case dropWhile (xs `elem` alpha) of                                                                      
    "" -> True                                                                                             
    ('.':ys) -> all (`elem` alpha) ys                                                                      
    _ -> False

compile errors :

/Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:26:19: error:
    • Couldn't match expected type ‘a0 -> Bool’ with actual type ‘Bool’
    • Possible cause: ‘elem’ is applied to too many arguments
     In the first argument of ‘dropWhile’, namely ‘(xs `elem` alpha)’
      In the expression: dropWhile (xs `elem` alpha)
      In the expression:
        case dropWhile (xs `elem` alpha) of
          "" -> True
         ('.' : ys) -> all (`elem` alpha) ys
         _ -> False
   |
26 |   case dropWhile (xs `elem` alpha) of
   |                   ^^^^^^^^^^^^^^^

/Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:26:29: error:
    • Couldn't match type ‘Char’ with ‘[Char]’
      Expected type: [String]
        Actual type: String
    • In the second argument of ‘elem’, namely ‘alpha’
      In the first argument of ‘dropWhile’, namely ‘(xs `elem` alpha)’
      In the expression: dropWhile (xs `elem` alpha)
   |
26 |   case dropWhile (xs `elem` alpha) of
   |                             ^^^^^

/Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:27:5: error:
    • Couldn't match expected type ‘[a0] -> [a0]’
                  with actual type ‘[Char]’
    • In the pattern: ""
      In a case alternative: "" -> True
      In the expression:
        case dropWhile (xs `elem` alpha) of
          "" -> True
          ('.' : ys) -> all (`elem` alpha) ys
          _ -> False
   |
27 |     "" -> True
   |     ^^

/Users/mgial/tech2/FUN_deBruijn_2017/app/Main.hs:28:6: error:
    • Couldn't match expected type ‘[a0] -> [a0]’
                  with actual type ‘[Char]’
    • In the pattern: '.' : ys
      In a case alternative: ('.' : ys) -> all (`elem` alpha) ys
      In the expression:
        case dropWhile (xs `elem` alpha) of
          "" -> True
          ('.' : ys) -> all (`elem` alpha) ys
          _ -> False
   |
28 |     ('.':ys) -> all (`elem` alpha) ys
   |      ^^^^^^

Final edit :

isValid :: String -> String -> Bool                                                                     
isValid "" alpha = True                                                                                 
isValid xs alpha =                                                                                         
  case dropWhile (`elem` alpha) xs of                                                                      
    "" -> True                                                                                             
    ('.':ys) -> all (`elem` alpha) ys                                                                      
    _ -> False

Upvotes: 1

Views: 286

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120741

With all (isAlphabet ys alpha), you try to first apply isAlphabet to the entire string ys and the alphabet, and then somehow pull the result of that through all. But, the types don't support this:

isAlphabet :: Char -> String -> Bool
               │         │       │
ys      ::   String      │       │
alpha   ::            String     │
all     ::                   (a->Bool) -> [a] -> Bool
What you instead want to do is use all to apply isAlphabet to each character individually. That's what it's there for.

  ... all (\c -> isAlphabet c alpha) ys ...

Note that if you'd defined the isAlphabet function which swapped arguments (which would be the more natural order) then you could shorten (eta-reduce) this to

isAlphabet :: String -> Char -> Bool

  ... all (isAlphabet alpha) ys ...

Alternatively you can use an operator section to directly apply the second argument. In fact I wouldn't bother defining isAlphabet in the first place, because it's actually an exact synonym for elem. Just write

  ... all (`elem` alpha) ys ...

all           :: (a->Bool) -> [a] -> Bool
                     │         │
(`elem`alpha) :: Char->Bool    │
ys            ::             String

Upvotes: 4

Related Questions