简体   繁体   中英

How to add letters of a String in a String list in Haskell?

I'm trying to add certain letters of a String in a String list.

For example: "Haskell" -> ['a', 's'] (only a and s )

After run I get the error message "Note in scope: xs ". So it lacks a list(I think). I have no problems to convert a list to a new list (eg mirrorList), but how can I "create" a list after I get a String Input?

letterList :: String -> [String]
letterList s = let x = head s in 
                     if x == 'a' || x == 's' then x:xs 
                     else letterList (tail x)

Before getting to your precise question, let's fix the types. Your example "Haskell" -> ['a', 's'] indicates that the type of this function is String -> String , not String -> [String] . Note that String is just a type alias for [Char] .

The error message means you have an expression that refers to a value xs , but nowhere have you defined anything named xs . I suspect you were going for with x:xs is pattern matching. The pattern goes to the left of the = , and that declares x and xs which you can refer to on the right side. And since the empty list can't be destructured into a head and tail, you need a separate case for it.

I'm guessing the result you're after looks something like this:

letterList :: String -> String
letterList []     = []
letterList (x:xs) = if x == 'a' || x == 's' then x:rest else rest
                    where rest = letterList xs

I assume your use of recursion here is just for practice, but for what it's worth, I would recommend writing this as

letterList :: String -> String
letterList = filter (`elem` "as")
  • Not in scope: xs

    That just means what it says: there is no variable called xs to be found, yet you attempt to use it. It's much the same error you'd also get in Java when trying to, say, call a method that's nowhere defined.

  • I have no problems to convert a list to a new list (eg mirrorList)

    That's something you never need in Haskell. When you have a list you can always use it directly and in whichever way you fancy. Because of referential transparency, there can never be a difference between a value and a copy of it. And I'm not sure what you mean by “converting” here, but generally it is avoided to convert anything in Haskell: parametric polymorphism usually allows you to generate the right type right from the beginning.

Now as to “how do I create a list” – you already do it! The cons (prepend) operator : in x:xs constructs a new list. ...Granted, it's based on the already existing list xs . This is in fact the only way to generate a new list, because the list constructor always needs a tail to prepend elements before. If you don't want/need/have any such list, use the empty one , [] , that's always available.


Even in Haskell, you sometimes need to work with mutable data (usually arrays in the ST monad – mutable internally but still guaranteed referentially transpart when viewed from the outside). Within such a computation, it may be necessary to copy an array, just like it can be in procedural languages.

The error message says - you are using xs on the right hand side but do not define it before its usage (ie no let statement before, no where statement after, and not on the left hand side either.

Aside from this answer

You have another problem is that you are basically implementing a filter, but the result type is a String not a [String] !

letterList :: String -> [String]
letterList [] = []
letterList (x:xs) = if x == 'a' || x == 's'
                      then [x]: letterList xs 
                      else letterList xs
  • The first case prevents an error if you supply an empty String !
  • the next line deconstructs the String in head = x and tail = xs , which is more readable and correct ( tail x is wrong you try to take the end of a single letter!)
  • next [x] transforms a single letter Char in a String = [Char] .

More elegant/homework

letterList str = [[x] | x <- str, x `elem` "as"]

this is called list comprehension, which would be the next "homework" I will give you to think about.

or

letterList str = map (\x -> [x]) $ filter (`elem` "as") str

Which uses higher order functions ( filter and map ) which is the second task I'll give you.

Edit

Of course you can also change the type signature to String -> String as @ChrisMartin shows - then you can omit the [ , ] in the [x] statements, and respectively omit the map (\\x -> [x]) thing.

似乎是复制粘贴错误:尝试将xs替换为(tail x)...,然后考虑emoty-list问题……也许您也将替换左侧的;-)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM