2014年1月23日木曜日

開発環境

Real World Haskell―実戦で学ぶ関数型言語プログラミング(Bryan O'Sullivan (著)、 John Goerzen (著)、 Don Stewart (著)、山下 伸夫 (翻訳)、伊東 勝利 (翻訳)、株式会社タイムインターメディア (翻訳)、オライリージャパン)の3章(型を定義し、関数を単純化する)、3.13(ガードの条件節の評価)、練習問題 12.を解いてみる。

その他参考書籍

練習問題 12.

コード(BBEdit)

Sample.hs

{-# OPTIONS -Wall -Werror #-}
module GrahamScan where

import qualified Data.List as List

type Point = (Double, Double)
data Direction = LeftTurn | Collinear | RightTurn
                deriving (Show, Eq)

grahamScan :: [Point] -> [Point]
grahamScan ps = let p = findLowestPoint ps
                    ps' = sortPoints p ps
                in grahamScanRecursive p ps'

grahamScanRecursive :: Point -> [Point] -> [Point]
grahamScanRecursive p (a:b:[])
    | d == LeftTurn = [a, b]
    | d == Collinear = [b]
     where d = getDirection a b p
grahamScanRecursive p (a:b:c:ps)
    | a == b = grahamScanRecursive p (a:c:ps)
    | a == c = grahamScanRecursive p (a:ps)
    | b == c = grahamScanRecursive p (a:b:ps)
    | d == LeftTurn = a:grahamScanRecursive p (b:c:ps)
    | otherwise = grahamScanRecursive p (a:c:ps)
     where d = getDirection a b c

grahamScanRecursive _ _ = undefined


findLowestPoint :: [Point] -> Point
findLowestPoint = foldr1 lowerPoint

lowerPoint :: Point -> Point -> Point
lowerPoint (a, b) (c, d)
    | b < d = (a, b)
    | b > d = (c, d)
    | a < c = (a, b)
    | otherwise = (c, d)

sortPoints :: Point -> [Point] -> [Point]
sortPoints p = List.sortBy (comparePoint p)

comparePoint :: Point -> Point -> Point -> Ordering
comparePoint p a b
    | a == b = EQ
    | t > 0 = LT
    | t < 0 = GT
    | fst a < fst b = LT
    | otherwise = GT
      where t = cow p a b

getDirections :: [Point] -> [Direction]
getDirections (a:b:c:xs) = getDirection a b c:getDirections (b:c:xs)
getDirections _ = []

getDirection :: Point -> Point -> Point -> Direction
getDirection a b c
    | t > 0 = LeftTurn
    | t < 0 = RightTurn
    | otherwise = Collinear
      where t = cow a b c

cow :: Point -> Point -> Point -> Double
cow (x1, y1) (x2, y2) (x3, y3) = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1)

kernel :: Point
kernel = (0.0, 0.0)

test :: [Point]
test = [
    kernel, (1.0, 0.0), kernel, (1.0, 1.0), kernel, (0.0, 1.0), kernel,
    (-1.0, 1.0), kernel, (-1.0, 0), kernel, (-1.0, -1.0), kernel, (0.0, -1.0),
    kernel, (1.0, -1.0)]

入出力結果(Terminal, インタプリタghci)

$ ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :load GrahamScan.hs 
[1 of 1] Compiling GrahamScan       ( GrahamScan.hs, interpreted )
Ok, modules loaded: GrahamScan.
*GrahamScan> let a = grahamScan test
*GrahamScan> a
[(-1.0,-1.0),(1.0,-1.0),(1.0,0.0),(1.0,1.0),(0.0,1.0),(-1.0,1.0)]
*GrahamScan> getDirections a
[LeftTurn,Collinear,LeftTurn,Collinear]
*GrahamScan> :quit 
Leaving GHCi.
$

0 コメント:

コメントを投稿