2012年3月25日星期日

SICP exercises in Haskell (Section 2.2.1)




-- Section 2.2.1
-- Exercise 2.17
last_pair :: [a] -> [a]
last_pair (x:[]) = [x]
last_pair (x:xs) = last_pair xs

-- Exercise 2.18
reverse' :: [a] -> [a]
reverse' xs = reverse'' xs []
  where reverse'' [] ys = ys
        reverse'' (x:xs) ys = reverse'' xs (x:ys)
        
-- Exercise 2.19        
cc :: (Num a, Ord a) => a -> [a] -> Int
cc amount coin_values
  | amount == 0 = 1
  | amount < 0 || no_more coin_values = 0
  | otherwise = cc amount 
                   (except_first_denomination coin_values)
                + cc (amount - 
                        (first_denomination coin_values)) 
                      coin_values
                

first_denomination :: [a] -> a
first_denomination = head

except_first_denomination :: [a] -> [a]
except_first_denomination = tail

no_more :: [a] -> Bool
no_more = null

Q: Does the order of the list coin-values affect the answer produced by cc? Why or why not? 
A: No, it won't. The algorithm is:
The number of ways to change amount a using n kinds of coins equals
  • the number of ways to change amount a using all but the first kind of coin, plus
  • the number of ways to change amount a - d using all n kinds of coins, where d is the denomination of the first kind of coin.
So, the order of the coin-values doesn't matter.

-- Exercise 2.20
-- The variadic function in Haskell is a little complicated.
-- See http://okmij.org/ftp/Haskell/polyvariadic.html#polyvar-fn
-- I skip this problem this time, and fix it later.


-- Exercise 2.21
square_list :: [Int] -> [Int]
square_list = map (^2)



-- Exercise 2.22
-- It's a inversed list because of the behavior of cons.
-- Cons always put the later value into the front of the list.

 



-- To be continued. :)


SICP exercises in Haskell (Section 2.1.4)


-- Section 2.1.4
-- Exercise 2.7
type Interval = (Float, Float)


make_interval :: Float -> Float -> Interval
make_interval x y = (x, y)


upper_bound :: Interval -> Float
upper_bound = snd


lower_bound :: Interval -> Float
lower_bound = fst


-- Exercise 2.8
sub_interval :: Interval -> Interval -> Interval
sub_interval x y =
  make_interval (lower_bound x - upper_bound y)
                (upper_bound x - lower_bound y)




-- To be continued. :)

2012年3月23日星期五

SICP exercises in Haskell (Section 2.1.3)


-- Section 2.1.3
-- Exercise 2.4
cons x y = \m -> m x y
car z = z (\p q -> p)
cdr z = z (\p q -> q)


-- Exercise 2.5
cons' a b = (2 ^ a) * (3 ^ b)
car' c = car'' c 0
  where car'' n count 
          | odd n = count
          | otherwise = car'' (n `div` 2) (count + 1)
cdr' c = cdr'' c 0
  where cdr'' n count
          | mod n 3 /= 0 = count
          | otherwise = cdr'' (n `div` 3) (count + 1)
                        
-- Exercise 2.6                        
-- zero f = \x -> x
zero = \f -> (\x -> x)        


-- add_1 n f = \x -> f ((n f) x)
add_1 n = \f -> (\x -> f ((n f) x))


-- one f = \x -> f x
one = \f -> (\x -> f x)


-- two f = \x -> f (f x)
two = \f -> (\x -> f (f x))


-- plus a b f = \x -> (a f . b f) x
plus a b = \f -> (\x -> (a f . b f) x)



SICP exercises in Haskell (Section 2.1.2)


-- Section 2.1.2                
-- Exercise 2.2
type Point = (Float, Float)
make_point :: Float -> Float -> Point
make_point x y = (x, y)


x_point :: Point -> Float
x_point = fst


y_point :: Point -> Float
y_point = snd


print_point :: Point -> String
print_point p = "(" ++ (show $ x_point p)
                ++ "," ++ (show $ y_point p)
                ++ ")"
                
type Segment = (Point, Point)
make_segment :: Point -> Point -> Segment
make_segment p1 p2 = (p1, p2)


start_segment :: Segment -> Point
start_segment = fst


end_segment :: Segment -> Point
end_segment = snd


midpoint_segment :: Segment -> Point
midpoint_segment s = make_point ((x1 + x2) / 2) ((y1 + y2) / 2)
  where x1 = x_point p1
        x2 = x_point p2
        y1 = y_point p1
        y2 = y_point p2
        p1 = start_segment s
        p2 = end_segment s




-- Exercise 2.3
data Rectangle = DiagonalLine Segment
               | DiagonalPoint Point Point
               deriving (Show)


width_rectangle :: Rectangle -> Float
width_rectangle (DiagonalLine seg) = abs (x2 - x1)
  where p1 = start_segment seg
        p2 = end_segment seg
        x1 = x_point p1
        x2 = x_point p2        
width_rectangle (DiagonalPoint p1 p2) = abs (x2 - x1)
  where x1 = x_point p1
        x2 = x_point p2
        
height_rectangle :: Rectangle -> Float        
height_rectangle (DiagonalLine seg) = abs (y2 - y1)
  where p1 = start_segment seg
        p2 = end_segment seg
        y1 = y_point p1
        y2 = y_point p2
height_rectangle (DiagonalPoint p1 p2) = abs (y2 - y1)        
  where y1 = y_point p1
        y2 = y_point p2
        
perimeter_rectangle :: Rectangle -> Float        
perimeter_rectangle rec = 2 * (height_rectangle rec 
                               + width_rectangle rec)
                          
area_rectangle :: Rectangle -> Float
area_rectangle rec = height_rectangle rec * width_rectangle rec
        

2012年3月21日星期三

SICP exercises in Haskell (Section 2.1.1)


-- Section 2.1.1
-- Exercise 2.1
type Rat = (Int, Int)


make_rat :: Int -> Int -> Rat
make_rat x y 
  | x < 0 && y < 0 = make_rat (-x) (-y)
  | x > 0 && y < 0 = make_rat (-x) (-y)
  | otherwise     = (x `div` d, y `div` d)
  where d = gcd x y                    


number :: Rat -> Int
number rat = fst rat


demon :: Rat -> Int
demon rat = snd rat


print_rat :: Rat -> String
print_rat rat = show (number rat) ++ 
                "/" ++ show (demon rat)