CS118 Programming Languages

Lecture 17 (Doug McIlroy)


Contents

  1. Haskell Summary
  2. Generating regular expression languages
  3. Parsing regular expressions

Assignment

some Haskell exercise

Haskell Summary

Haskell is like ML in many ways

  • polymorphic
  • inspired by lambda calculus and type theory
  • pattern-matching
  • excellent for structural induction

Different in modest ways

  • consistently more concise (and perspicuous, IMHO)
  • no val,fun,rec,and
  • different representation of some operators
    ML as @ :: : <> andalso orelse (*...*)
    Hs @ ++ : :: /= && || --...
  • type and constructor names are capitalized

And profoundly different in others

  • rigorously functional; no references
  • call by need vs call by value
  • type classes and operator overloading
  • infinite data structures
  • quite different module facilities

Typical function declarations


ML      head : 'a list -> 'a;
        fun head (x::_) = x;  

Hs      head :: [a] -> a
        head (x:xs) = x

ML      fact : int -> int
        fun fact 0 = 1
          | fact n = n*(fact (n-1))

Hs      fact :: Int -> Int
        fact 0 = 1
        fact n = n*(fact (n-1))
Note: types begin with upper case letter by convention
ML      datatype ('a,'b) pair = Pair of 'a*'b;

Hs      data Pair a b = Pair a b
Alternative, might have written any of the following with different meanings
data Pair a b = Pair a b
data Pair a b = Pair (a, b)
data Pair a b = Pair [a] [b]


ML      datatype 'a tree = Empty | Tree of ('a tree, 'a, 'a tree);

Hs      data Tree a = Empty | Tree (Tree a) a (Tree a)

ML      fun map _ [] = []
          | map f (x::xs) = f x :: map f xs;

Hs(1)   map _ [] = []
        map f (x:xs) = f x : map f xs

Hs(2)   map f xs = [f x | x<-xs]    -- like set comprehension: {f x | x \(mo xs}

ML      fun cross [] _ = []        -- cross [1,2] [3,4] = [(1,3),(1,4),(2,3),(2,4)]
          | cross _ [] = []
          | cross xs ys = map (fn(x)=>map (fn(y)=>(x,y)) ys) xs;

Hs      cross [] _ = []
        cross _ [] = []
        cross xs ys = [(x,y) | x<-xs, y<-ys]

Hs      zip [] _ = []
        zip _ [] = []
        zip (x:xs) (y:ys) = (x,y) : zip xs ys

        zipWith _ [] _ = []
        zipWith _ _ [] = []
        zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys

Haskell specials


zeroes = 0 : zeroes               -- infinite sequence of zeroes

ints = [1..]

powersof2 = [2^x | x<-ints]

Type classes and overloading


Eq                                -- things that can be compared for equality
Ord                               -- things that can be compared for order
Num                               -- operands of + - * negate ...
Fractional                        -- operands of / recip ...

(+) :: Num a => a -> a -> a       -- + applies to 2 things of the same type in class Num


Power series represented as a list of coefficients


instance Num a => Num [a] where    -- if type a is in class Num then lists of a are in Num
	_ + [] = []
	[] + _ = []
	(x:xs) + (y:ys) = x+y : xs+ys
--      xs + ys = zipWith (+) (xs++zeroes) (ys++zeroes) -- one-line form
        negate xs = [-x | x<-xs]
        _ * [] = []
        [] * _ = []
        (x:xs) * ys@(y:yt) = x*y : [x]*yt + xs*ys
        fromInteger c = [c]        -- coerce any Integer type to power series over that type

instance Fractional a => Fractional [a] where
        ...

integral [] = []
integral xs = 0 : zipWith (\x y->x*(recip y)) xs [1..]

expx = 1 + integral expx

cosx = 1 - integral sinx
sinx = integral cosx

For more information: http://www.haskell.org
The Hugs interpreter: /usr/contrib/bin/hugs
The standard prelude: /usr/contrib/src/hugs/lib/Prelude.hs (Haskell standard functions defined in Haskell -- good source of examples)

Generating regular expression languages

-- FILE:    enum_re.hs
-- PURPOSE: Enumerate the strings for a regular expression, 
-- ordered by length and lexicographically within length.
--   enum "a(b|c)|d" == ["d","ab","ac"]
--   enum "(b|ab*a)*" == ["","b","aa","bb","aab","aba","baa","bbb",...

type Lang = [String]
cmp       :: String -> String -> Ordering
enum      :: String -> Lang
alt, cat  :: Lang -> Lang -> Lang
clo       :: Lang -> Lang

cmp x y = compare (length x, x) (length y, y)

enum s = parse [] s

alt [] ys = ys                 -- alternation (merge languages)
alt xs [] = xs
alt xs@(x:xt) ys@(y:yt) = case cmp x y of
	LT -> x : alt xt ys
	EQ -> x : alt xt yt
	GT -> y : alt xs yt

cat [] _ = []                 -- catenation (cross product of languages)
cat _ [] = []
cat (x:xt) ys@(y:yt) =
	(x++y) : alt (cat [x] yt) (cat xt ys)

clo [] = [""]                 -- Kleene closure
clo ("":xs) = clo xs
clo xs = "" : cat xs (clo xs)

Parsing regular expressions

-- FILE:    parse_re.hs
-- PURPOSE: parse regular expressions
-- MODS:    2002.05.21 -- original -- MD McIlroy

-- shift-reduce parser; stack symbol holds its language

data Syntax  = P Lang  -- Primary     ::= letter | "()" | "(" A ")"
             | C Lang  -- Catenation  ::= P | P "*" | C C
             | A Lang  -- Alternation ::= C | A "|" A
             | L       -- "("
type Stack = [Syntax]

parse :: Stack    ->   String -> Lang
parse (P(x):z)         ('*':s) = parse (C(clo x):z)        s
parse (P(x):z)               s = parse (C(x):z)            s
parse (C(y):C(x):z)          s = parse (C(cat x y):z)      s
parse (C(x):z)         ('|':s) = parse (A(x):z)            s
parse (C(x):z)         (')':s) = parse (A(x):z)      (')':s)
parse (C(x):z)              "" = parse (A(x):z)           ""
parse (A(y):A(x):z)          s = parse (A(alt x y):z)      s
parse (A(x):L:z)       (')':s) = parse (P(x):z)            s
parse (L:z)            (')':s) = parse (P([""]):z)         s
parse z                ('(':s) = parse (L:z)               s
parse z      (c:s) | isAlpha c = parse (P[[c]]:z)          s
                   | otherwise = error ("syntax at "++(c:s))
parse [A(x)]                "" = x
parse _                     "" = error "unexpected end"

go to:

CS118
Home Page
CS118
Summary
Previous
Lecture
Next
Lecture