Chapter 3: Strings¶
3.1 Printing strings¶
In this chapter we’ll learn about the String
type, use a few list
processing functions, go over some basic syntax, and interact with the
repl.
3.2 A first look at types¶
Strings are represented as lists of UTF-16 characters. They are enclosed in double quotes. Single quotes are reserved for characters.
When you query the type of a string in the repl, its composite nature becomes apparent:
Prelude> :type "Hello!"
"Hello!" :: [Char]
Sometimes you may see String
in type signatures. This is really a
type alias for [Char]
.
3.4 Top-level versus local definitions¶
Top-level declarations are declarations that are visible anywhere within a module. In other words, they aren’t nested within other functions.
You can use let
, and lambdas to create definitions local to an
expression.
The where
keyword can be used to create definitions that are
local to a declaration.
3.4.1 Exercises: Scope¶
These lines of code are from a REPL session
Prelude> x = 5 Prelude> y = 7 Prelude> z = x * y
Is
y
in scope forz
?Yes, and here’s proof:
·∾ x = 5 ·∾ y = 7 ·∾ z = x * y ·∾ z 35
These lines of code are from a REPL session:
Prelude> f = 3 Prelude> g = 6 * f + h
Is
h
in scope forg
? Go with your gut here.No, we haven’t defined
h
anywhere that I can see. Proof:·∾ f = 3 ·∾ g = 6 * f + h <interactive>:7:13: error: Variable not in scope: h
This code sample is from a source file:
area d = pi * (r * r) r = d / 2
Is everything we need to execute
area
in scope?Well, no. Since
d
isn’t defined, there should be some sort of error:·∾ :l area.hs [1 of 1] Compiling Main ( area.hs, interpreted ) area.hs:2:5: error: Variable not in scope: d | 2 | r = d / 2 | ^ Failed, no modules loaded.
This code is also from a source file:
area d = pi * (r * r) where r = d / 2
Now are
r
andd
in scope forarea
?In this case, yes. This is because
r
is now local to the area functions scope, the parameterd
is visible to it:·∾ :l tst.hs [1 of 1] Compiling Main ( tst.hs, interpreted ) Ok, one module loaded. ·∾ area 88 6082.12337734984
3.5 Types of concatenation functions¶
(++)
append to a string or listconcat
concatenate a list of lists or strings
3.7 More list functions¶
(:)
prepend to a list or stringhead
take the first elementtail
take the last elementtake
taken
elementsdrop
removen
elements from the beginning(!!)
get an element at an index
3.8 Chapter Exercises¶
3.8.1 Reading syntax¶
For the following lines of code, read the syntax carefully and decide if they are written correctly. Test them in your REPL after you’ve decided to check your work. Correct as many as you can.
Original:
concat [[1,2,3],[4,5,6]]
,Prediction: This will work as intended.
Result:
·∾ concat [[1,2,3],[4,5,6]] [1,2,3,4,5,6]
Original:
++ [1,2,3] [4,5,6]
Prediction: Since
++
needs parenthesis in order to be used prefix, this will fail.Result:
·∾ ++ [1,2,3] [4,5,6] <interactive>:2:1: error: parse error on input ‘++’
Original:
(++) "hello" " world"
Prediction: This should output
"hello world"
.Result:
·∾ (++) "hello" " world" "hello world"
Original:
["hello" ++ " world]
Prediction: Because this is missing a closing double quote, it will fail with a parse error.
Result:
·∾ ["hello" ++ " world] <interactive>:4:21: error: lexical error in string/character literal at end of input
Original:
4 !! "hello"
Prediction: Since the arguments are in the wrong order, it will result in a type error.
Result:
·∾ 4 !! "hello" <interactive>:6:1: error: • Non type-variable argument in the constraint: Num [a] (Use FlexibleContexts to permit this) • When checking the inferred type it :: forall a. Num [a] => a
Original:
(!!) "hello" 4
Prediction: This should return
'o'
.Result:
·∾ (!!) "hello" 4 'o'
Original:
take "4 lovely"
Prediction:
take
is missing an argument.4
should be outside the quotes. This will result in some kind of error.Result:
·∾ take "4 lovely" <interactive>:8:6: error: • No instance for (Data.String.IsString Int) arising from the literal ‘"4 lovely"’ • In the first argument of ‘take’, namely ‘"4 lovely"’ In the expression: take "4 lovely" In an equation for ‘it’: it = take "4 lovely"
Original:
take 3 "awesome"
Prediction:
"awe"
Result:
·∾ take 3 "awesome" "awe"
Read the code and figure out which results came from which lines of code. Be sure to test them in the REPL.
concat [[1 * 6], [2 * 6], [3 * 6]]
–> d)[6,12,18]
:·∾ concat [[1*6],[2*6],[3*6]] [6,12,18]
"rain" ++ drop 2 "elbow"
–> c)"rainbow"
:·∾ "rain" ++ drop 2 "elbow" "rainbow"
10 * head [1, 2, 3]
–> e)10
:·∾ 10 * head [1,2,3] 10
(take 3 "Julie") ++ (tail "yes")
–> a)"Jules"
:·∾ (take 3 "Julie") ++ (tail "yes") "Jules"
concat [tail [1, 2, 3], tail [4, 5, 6], tail [7, 8, 9]]
–> b)[2,3,5,6,8,9]
·∾ :{ ⋮ concat [ tail [1,2,3] ⋮ , tail [4,5,6] ⋮ , tail [7,8,9] ⋮ ] ⋮ :} [2,3,5,6,8,9]
3.8.2 Building functions¶
Write functions in your repl to transform these inputs to their corresponding outputs using only the list processing features mentioned in the chapter [#1]. Don’t write a general purpose function – these only need to work for the inputs provided.
Given
"Curry is awesome"
return"Curry is awesome!"
Given
"Curry is awesome!"
return"y"
Given
"Curry is awesome!"
return"awesome!"
Now take each of the above and rewrite it in a source file as a general function that can take different string inputs.
a x = x ++ "!" b x = if x == "Curry is awesome!" then "y" else "n" c x = drop 9 x
Write a function of type
String -> Char
that returns the third character in aString
.thirdLetter x = x !! 2
This should return the character from
"Curry is awesome!"
at the requested position (index + 1).letterIndex x = "Curry is awesome!" !! (x-1)
Write a function called
rvrs
that takes the string"Curry is awesome"
and returns"awesome is Curry"
. You’re expected only to slice and dice this particular string withtake
anddrop
, not write a general purpose function.Put
rvrs
in a module and run it.
Footnotes