| CS 291 | University of Puget Sound | Spring, 2020 |
|
Programming Language Paradigms:
|
||
|
Explorations with Functional Problem Solving (supported by Scheme/Haskell)
and Declarative Prblem Solving (supported by Prolog) |
||
| Scheme | Language | Haskell | |||
|---|---|---|---|---|---|
| Topic | Syntax | Example | Comparison(s) | Syntax | Example |
| starting environment (after installation) | scheme | typed in command line | after installation, Haskell requires creating each new project | for a new project, you need to
| for a new project projectName
(note: no dashes allowed in programName), type in a terminal window: stack new projectName cd project-name stack setup stack build stack ghci |
| load file | (load "—") | (load "filename.ss") | slightly abbreviated in Haskell | :l filename, where stored file is filename.hs in the project directory (here: l is a lower case L) | :l filename |
| comments | comments start with a semicolon and continue to the end of the line | (f x) ; comment for f(x)
| Scheme and Haskell allow single-line comments; only Haskell allows multi-line comments | single-line comments start with two dashes –
– multiple-line comments start with {- and end with -} |
{- this is a
multi-line
comment -}
|
| variable typing | variables can have any type, and types can be mixed (e.g., in a list) | (1 "two" [3 4] ()) | Scheme flexible; Haskell not | types inferred or explicitly declared; once determined cannot change | [1, 2, 3, 4] ok [1, "two", [3, 4], [ ] ] not ok |
| numbers | Operators on mixed types change integers to fractions to reals | (/ 2 5) yields fraction 2/5 | by default, numbers have type Num | Real, Rational, Integer types available For conversions, see Tutorial 10 Numbers, section 10.3 often negative numbers should be written in parentheses | 2 / 5 yields real number 0.4 (-7) denotes negative 7 |
| Boolean types and operators |
| Haskell expands Scheme's list of operators | (not (< a b c))
| notElem example: [x | x <- "abcdefghijklmnopqrstuvwxyz", x `notElem` "aeiou" ] | |
| arithmetic | operations +, -, *, / arguments must be numbers | n-ary operations use prefix notation (+ 2 3 4) | different notational systems used for expressions | operations +, -, *, / arguments must be numbers |
|
| lists | use parentheses with spaces | (2 3 4 5) and ("one" "two" "three") | lists built in to both languages | use square brackets with commas | [2, 3, 4, 5] and ["one", "two", "three"] |
| primitive list extractors | car, cdr | (car '(1 2)) yields 1 | car equivalent to head; cdr equivalent to tail; | head, tail, last (return last element), init (return all but last) | init [1, 2, 3] yields [1, 2] |
| primitive list constructor | cons | (cons 3 '(5 4 6)) ===> (3 4 5 6) | mostly a change in format, although Haskell lists may contain only elements of the same type | : operator | 3 : [4, 5, 6] ===> [3, 4, 5, 6] |
| both Scheme and Haskell have extensive list operators | See Scheme lists | Many operations are equivalent, but sometimes with different names | See Data.List | ||
| defining lists | list elements are placed in parentheses (often with an initial quote) | '(3 1 4 1 5 9 2)
| Haskell extends options available in Scheme |
|
[1 .. 7] ===> [1, 2,3, 4, 5, 6, 7]
[1, 3 .. 7] ===>[1, 3, 5, 6]
[-3 .. 3] ===> [-3, -1, 1, 3]
[x | x <- [1 .. ], (mod x 2) == 0]
===> list of all positive even integers
take 7 [x | x <- [1 .. ], (mod x 2) == 0]
===> [2,4,6,8,10,12,14]
|
| flexible typing versus strongly typed | variables can have any type, and types can be mixed (e.g., in a list) | (1 "two" [3 4] ()) | Scheme flexible; Haskell not | types inferred or explicitly declared and cannot change | [1, 2, 3, 4] — ok [1, "two", [3, 4], [ ] ] — not ok |
| strings | strings are a specified type | "this is a string" | Strings in Haskell not a separate type | String in Haskell considered a list of characters | "Computer" is considered ['C', 'o', 'm', 'p', 'u', 'p', 't', 'e', 'r'] |
| built-in functions | extensive library | call with parentheses and prefix notation: (func-name parameters) | consistent prefix notation in Scheme; prefix notation without parentheses for named functions in Haskell, but infix notation for arithmetic | extensive library | call with func-name parameters (no parentheses): f x y |
| function definitions | start with (define func-name (lambda (parameters) ... | (define f (lambda (x y) | same concepts, Haskell's syntax is somewhat simpler | start with funcName parameters = initial word let usually optional separate name and parameters by spaces | f x y = Note: if f is a user-defined, two-parameter function, then it may be called in prefix form f x y or as an
infix operator (if used with backquotes) x `f` y
|
| if-statements | Basic syntax with parentheses: |
(if
then-action
else-action)
| else optional in Scheme, not in Haskell; if else-action in Scheme, both can be used within more extensive expressions | Basic syntax with then, else—must always return something |
if (condition)
then then-action
else else-action
|
| bindings | use define for globals; let, let*,
letrec for locals
| (define pi 3.1415926535) | within a function, once bound, values cannot change | let often optional in definitions | pi = 3.1415926535 |
| tuples (in Haskell) | not explicitly available, although lists could be used | Scheme lists can contain different types and can be of
different lengths Haskell tuples can contain different types, but each tuple must have the same length. | See the reading on Tuples | ||
(This is provides an implementation for the length functions in both Scheme and Haskell.)
(define mycount
(lambda (lst)
(mycount-kernel 0 lst)
) )
(define mycount-kernel
(lambda (count-so-far ls)
(if (null? ls)
count-so-far
(mycount-kernel (+ 1 count-so-far) (cdr ls))
) ) )
myCount lst = myCountKernel 0 lst
myCountKernel countSoFar ls =
if (ls == [ ])
then countSoFar
else myCountKernel (1 + countSoFar) (tail ls)
This worksheet marks a transition in the course from working with functional problem solving with Scheme to functional problem solving with Haskell. Thus, this lab considers problem done previously in Scheme. For this lab,
if-then-else conditionals should be used
as needed (never patterns or guards).
Write a function to implement f(x) = x2 - 3x +
2, and evaluate the function for x = 0, 1, 2, 3,
4.
Define a procedure that computes the volume of a sphere, given its radius.
Define a procedure that, given the radius of a circle, returns its circumference and area on a list.
Write a function classify that has a number as a
parameter and returns the appropriate string: "negative",
"zero", or "positive".
Write a function byTwos that with two parameters (a
starting and ending value) and returns a list of numbers
beginning at the starting number and progressing in increments
of 2 until the ending value is exceeded.
byTwos 1 11 ===> [1, 3, 5, 7, 9, 11]
byTwos 1 10 ===> [1, 3, 5, 7, 9]
byTwos 2 9 ===> [2, 4, 6, 8]
byTwos (-7) 7 ===> [-7, -5, -3, -1, 1, 3, 5, 7]
Note: this can be done directly in Haskell, no need for recursion!
classify -7 ===> "negative"
classify 0 ===> "zero"
classify 3.141592 ===> "positive"
Define Texas ranges for the following:
[(-2) .. 5]
[-1 .. 5]
[(-1.3) .. 3.3]
[2.5 .. 7.7]
[2.5, 3 .. 6]
[2.5, 3, 3.5 .. 6]
[6 .. 2]
In each case, indicate what result is obtained, and briefly explain why.
Explain what the following function does and explain why.
niceList value = (take value (cycle [3, 1, 4, 1, 5]))
Consider the following function.
niceList value = (take (5*value) (repeat value))
Write a function myRepeat with
parameter value that returns a list
with value copies of 1, 2, 3, ...,
value
myRepeat 1 ===> [1]
myRepeat 3 ===> [1, 2, 3, 1, 2, 3, 1, 2, 3]
myRepeat 0 ===> [ ]
Consider multiples of either 11 or 13.
multiples11Or13 which has an integer
parameter num and returns a list of the
first num multiples of 11 or 13.
multiples11Or13 1 ===> [11]
multiples11Or13 2 ===> [11, 13]
multiples11Or13 5 ===> [11, 13, 22, 26, 33]
Write a function identifyConsonants that takes a
string as parameter and returns a string of all uppercase and
lowercase consonants.
identifyConsonants "This is A TEsT" ===> "ThssTsT"
Hint: Look at the examples in the reading on list comprehensions.
Computing a Polynomial
A polynomial function has the form
p(x) = anxn + an-1xn-1 + ... + a2x2 + a1x + a0
Write a Haskell function computePoly that takes two parameters:
and returns the value of the polynomial p(x).
Notes:
|
created 8 February 2020 revised 10 February 2020 |
|
| For more information, please contact Henry M. Walker at walker@cs.grinnell.edu. |