Yes, absolutely! That's one of the beautiful things about Haskell.
You can treat Strings as [Char]. In fact, that's what they are!
In GHCi, type :i String - you get type String = [Char].
You can easily compose functions. There's an operator for that, (.). So (f . g) x is f (g x).

I would improve the code in a few key ways.
Firstly, make the replaceBlank function more general, so it takes a condition and a replacement function.
Secondly, compose all the functions in a "main" function, as you call it.
But do not name the main function main! That name is reserved for the IO action of a program.

It's also important not to think of the final function as "calling" the other functions.
That is imperative terminology, here, we are applying the function(s).

Also, why does your dropInvalids contain a toUpperStr? You never specified the string to be all uppercase in the end.

Also also, be sure to declare the type of your functions.

In this case, the following would be the correct code:

import Data.Char

dropInvalids :: [Char] -> [Char]
dropInvalids = filter (\x -> isLetter x || isSpace x || isDigit x)
    -- isLetter exists

replace' :: (a -> Bool) -> (a -> a) -> [a] -> [a]
replace' _ _ [] = []
replace' f g (x:xs) =
            if f x
            then g x : replace' f g xs
            else x : replace' f g xs
    -- To replace one value with another, use replace (== a) (const b).

replaceWith :: (a -> Bool) -> a -> [a] -> [a]
replaceWith f b = replace' f (const b)

replace :: Eq a => a -> a -> [a] -> [a]
replace a b = replace' (== a) (const b)
  -- The Eq makes sure you can check for equality.

manipulateString :: [Char] -> [Char]
manipulateString = replace 'A' 'Z' . replace 'a' 'z' . replaceWith isDigit ' ' . replace ' ' '_' . dropInvalids
Answer from schuelermine on Stack Overflow
🌐
Hackage
hackage.haskell.org › package › strings-1.1 › docs › Data-Strings.html
Data.Strings - Hackage - Haskell
The Str class provides functions for working with arbitrary Strings. It is basically the same interface as provided by the Strings class. However, every input string is a Haskell String here, thus easing the usage of different string types with native Haskell String literals.
Discussions

String manipulation haskell - Stack Overflow
In the following exercise i want to manipulate a random string input by using functions. Step 1: I want to remove all characters which are not digits, letters or spaces Step 2: I want to replace ... More on stackoverflow.com
🌐 stackoverflow.com
Text or String
Yes, when representing text (that could be unicode), you want to almost always prefer Text over String. Text points to a packed, contiguous block of memory holding unicode data, whereas String is a linked list of characters. Each element in the linked list takes 12 bytes and another memory lookup. IMO the only time String should be used is when interacting with standard library functions that accept String. It's easy to get a String from Text by using unpack. More on reddit.com
🌐 r/haskell
60
17
November 6, 2015
Haskell String Types

I don't think I'd really call ByteString a string type...it has no semantics for being a string, and really is supposed to encapsulate nothing more meaningful than a list or array (depending on lazy or strict) of bytes. "Converting a string to a bytestring" doesn't really make much sense...what encoding are you encoding it in? The choice is ambiguous and comes down to weird implementation quirks and hacks and doesn't actually make sense in the context of what a String is...and doesn't pay any respect to the semantics of String and so is more or less a meaningless conversion.

Text is actually designed to be a semantic encoding-agnostic container (following unicode standards). It's supposed to be able to understand text as text, regardless of encoding. So, that means that from the encoding functions in Data.Text.Encoding, it can decode encoded bytestrings from different encodings (utf8, utf16, etc., anything you'll probably encounter in the real world) and it can encode to bytestrings from different encodings, as well. Text operations deal with text and are an abstraction over whatever encoding they might be in.

Think of it this way. I have a program that uses a lot of Ints. Should I go in and replace every 4 with "4" :: String? No, that's pretty silly. 4 the Int gives me a powerful API to deal with Ints as Ints -- they can be added, subtracted, multiplied, converted to different numerical formats...if I want to work with integers, I'd use 4 and not "4". "4" to do arithmetic is just silly. Can you imagine fib :: String -> String, which takes a String representing an Int and returns another String representing an Int?

It's the same thing for ByteString and Text. Text represents text in a meaningful way and has an API for manipulating text. But using ByteString to store text is like using "4" to store numbers. It doesn't even make sense to store numbers as strings...there's more than one way! What if you wanted to encode 4 as "four" instead? And there's no API in bytestring to deal with text. It just doesn't represent text...it represents a string of bytes. And ByteString can really mangle your text if you don't pay attention to the implementation detail and exact quirks of the hack you are doing.

More on reddit.com
🌐 r/haskell
25
30
September 7, 2015
String types in Haskell (+ rare ones)

and you must process them correctly, text-icu will be indispensable.

Instead of text-icu I can recommend unicode-transforms package:

  • https://github.com/composewell/unicode-transforms

hk_hooda gave a talk at Functional Conf about performance optimizations he made to make this library blazingly fast. So I would give it a try!

More on reddit.com
🌐 r/haskell
8
61
January 7, 2019
🌐
Haskell Community
discourse.haskell.org › links
The ultimate guide to Haskell Strings - Links - Haskell Community
May 12, 2024 - Tiny comment about the OsPath, PosixPath and WindowsPath section: perhaps it should be emphasized that these types live in the filepath package? Also, perhaps that section could directly follow the OsString, PosixString and WindowsString section · Speaking of file-io, the difference between ...
🌐
Hasufell
hasufell.github.io › posts › 2024-05-07-ultimate-string-guide.html
The ultimate guide to Haskell Strings · Hasufell's blog
May 7, 2024 - Now that we know what a Unicode Code Point is, we also understand that the Haskell String type has essentially no text encoding. It is just a linked list of those code points (a subset of Int, in fact). This can be a nice property, e.g.
🌐
Monday Morning Haskell
mmhaskell.com › blog › 2017 › 5 › 15 › untangling-haskells-strings
Untangling Haskell's Strings — Monday Morning Haskell
December 9, 2023 - The String type is the most basic form of representing strings in Haskell. It is a simple type synonym for a list of unicode characters (the Char type). So whenever you see [Char] in your compile errors, know this refers to the basic String type.
Top answer
1 of 1
2

Yes, absolutely! That's one of the beautiful things about Haskell.
You can treat Strings as [Char]. In fact, that's what they are!
In GHCi, type :i String - you get type String = [Char].
You can easily compose functions. There's an operator for that, (.). So (f . g) x is f (g x).

I would improve the code in a few key ways.
Firstly, make the replaceBlank function more general, so it takes a condition and a replacement function.
Secondly, compose all the functions in a "main" function, as you call it.
But do not name the main function main! That name is reserved for the IO action of a program.

It's also important not to think of the final function as "calling" the other functions.
That is imperative terminology, here, we are applying the function(s).

Also, why does your dropInvalids contain a toUpperStr? You never specified the string to be all uppercase in the end.

Also also, be sure to declare the type of your functions.

In this case, the following would be the correct code:

import Data.Char

dropInvalids :: [Char] -> [Char]
dropInvalids = filter (\x -> isLetter x || isSpace x || isDigit x)
    -- isLetter exists

replace' :: (a -> Bool) -> (a -> a) -> [a] -> [a]
replace' _ _ [] = []
replace' f g (x:xs) =
            if f x
            then g x : replace' f g xs
            else x : replace' f g xs
    -- To replace one value with another, use replace (== a) (const b).

replaceWith :: (a -> Bool) -> a -> [a] -> [a]
replaceWith f b = replace' f (const b)

replace :: Eq a => a -> a -> [a] -> [a]
replace a b = replace' (== a) (const b)
  -- The Eq makes sure you can check for equality.

manipulateString :: [Char] -> [Char]
manipulateString = replace 'A' 'Z' . replace 'a' 'z' . replaceWith isDigit ' ' . replace ' ' '_' . dropInvalids
🌐
Lotz84
lotz84.github.io › haskellbyexample › ex › string-functions
Haskell by Example: String Functions
Haskell by Example: String Functions · original · import Data.List import Data.Char include :: String -> String -> Bool include xs ys = or . map (isPrefixOf ys) . tails $ xs joinWith :: [String] -> String -> String joinWith xs sep = concat . init . concat $ [[x, sep] | x <- xs] split :: String ...
Find elsewhere
🌐
HaskellWiki
wiki.haskell.org › Strings
Strings - Haskell « HaskellWiki
March 2, 2014 - String is the only string type mandated by the language standard, and as such is overwhelmingly the most common, especially for non-performance-sensitive applications.
🌐
FPBlock Academy
academy.fpblock.com › haskell › tutorial › string-types
String Types
The final choice is String, which is the only string-like type defined in the base package. It is actually just a type synonym type String = [Char]. While this type is conceptually simple, it is highly inefficient (as mentioned above).
🌐
Aelve
guide.aelve.com › haskell › strings-o62hqc69
Strings – Haskell – Aelve Guide
String is the standard string type from Prelude, is widely used, and is rather easy to work with, as it's simply a synonym for [Char] and all list functions work with String out of the box. This representation is very convenient, but is neither fast nor memory-efficient.
🌐
ZVON
zvon.org › other › haskell › Outputprelude › String_d.html
Haskell : String
Enjoy! ZVON team Any suggestions send to webmaster@zvon.org, please
🌐
HaskellWiki
haskell.org › haskellwiki › Strings
Strings - HaskellWiki
March 2, 2014 - String is the only string type mandated by the language standard, and as such is overwhelmingly the most common, especially for non-performance-sensitive applications.
🌐
Cofree
free.cofree.io › 2020 › 05 › 06 › string-types
Eat Haskell String Types for Breakfast
May 6, 2020 - Haskell has five commonly used string types: String, strict and lazy Text, and strict and lazy ByteString1.
🌐
Real World Haskell
book.realworldhaskell.org › read › characters-strings-and-escaping-rules.html
Appendix B. Characters, strings, and escaping rules
Haskell's escaping rules follow ... is surrounded by ASCII single quotes, ', and has type Char. ... A string literal is surrounded by double quotes, ", and has type [Char] (more often written as String)....
🌐
EDUCBA
educba.com › home › software development › software development tutorials › programming languages tutorial › haskell string
Haskell String | How String Type Works in Haskell | Examples
May 31, 2023 - Haskell string is a data type which is used to store the value of variable in the form of string, string is represented by the sequence of character in Haskell or in any other programming language as well.
Address   Unit no. 202, Jay Antariksh Bldg, Makwana Road, Marol, Andheri (East),, 400059, Mumbai
🌐
HaskellWiki
wiki.haskell.org › Tutorials › Programming_Haskell › String_IO
Tutorials/Programming Haskell/String IO - HaskellWiki
October 22, 2021 - The type, once again, tells the story. lines takes a string, and breaks it up into a list of strings, splitting on newlines. To join a list of strings back into a single string, inserting newlines, we'd use the ...
🌐
Learn You a Haskell
learnyouahaskell.com › input-and-output
Input and Output - Learn You a Haskell for Great Good!
It's just a normal function that takes a string like "hey there man" and then calls words with it to produce a list of words like ["hey","there","man"]. Then we map reverse on the list, getting ["yeh","ereht","nam"] and then we put that back into one string by using unwords and the final result is "yeh ereht nam". See how we used function composition here. Without function composition, we'd have to write something like reverseWords st = unwords (map reverse (words st)). What about main? First, we get a line from the terminal by performing getLine call that line line. And now, we have a conditional expression. Remember that in Haskell, every if must have a corresponding else because every expression has to have some sort of value.
🌐
Reddit
reddit.com › r/haskell › text or string
r/haskell on Reddit: Text or String
November 6, 2015 -

When starting a new project, should I try to use only Text?

i.e. do not use String

Top answer
1 of 5
18
Yes, when representing text (that could be unicode), you want to almost always prefer Text over String. Text points to a packed, contiguous block of memory holding unicode data, whereas String is a linked list of characters. Each element in the linked list takes 12 bytes and another memory lookup. IMO the only time String should be used is when interacting with standard library functions that accept String. It's easy to get a String from Text by using unpack.
2 of 5
14
A few weeks ago I tried to optimize a heavily text oriented program and I got a bit of experience that might be worth sharing. Don't forget to enable the OverloadedStrings in GHC, since Text is an instance of IsString, or otherwise you will have a hard time using Texts. Generally, I prefer Text over String, but there are certain cases that String works better. Text vs. String is just like Array vs. LinkedList. Are arrays better than linked lists? For most use cases yes, because they take less memory and have a faster access time. But for certain operations, like cons, Strings are faster, because you don't need to copy the second one to the new memory. Try to understand why Text.length takes O(n) to run (while length of arrays can be obtained in constant time) and it helps you a lot. That's because Text internally keeps an array of bytes with UTF-8 encoding, in which some of the chars are 1 byte and some others are multi-byte. It has to go over all the chars to detect which one is which. (Edit: It seems that Text encoding is UTF-16. See the comments below, but anyways, it doesn't change my point.) Text.concat [t1, t2, ..., tn] is much faster than t1 <> t2 <> ... <> tn (O(n) vs. O(n^2)). Use Lazy Text and Text Builder if you want to do a lot of appends. You can use <> and IsString instance with both of them as well. Edit 2: I forgot to mention this one: String does not check for validity of code points. You may end up with a string that contains invalid UTF code points. But Text is stricter about that. It may not be so important in most applications. But you may see some weird behaviour when comparing Strings with invalid chars: they may looks the same but == returns False.
🌐
HaskellWiki
wiki.haskell.org › Cookbook › Lists_and_strings
Cookbook/Lists and strings - Haskell « HaskellWiki
June 1, 2019 - In Haskell, lists are what Arrays are in most other languages. The list of all squares can also be written in a more comprehensive way, using list comprehensions: ... Since strings are lists of characters, you can use any available list function.