-- gps.hs: General Program Synthesis Benchmark Suite
--
-- Copyright (C) 2021-2025 Rudy Matela
-- Distributed under the 3-Clause BSD licence (see the file LICENSE).
{-# LANGUAGE CPP #-}
import Conjure
import System.Environment (getArgs)
import Data.Char (isLetter) -- GPS bench #5
import Data.Char (isSpace) -- GPS bench #7
import Data.Ratio ((%), numerator, denominator) -- GPS bench #10
import Data.List (findIndex) -- GPS bench #12
import Data.Maybe (fromJust) -- GPS bench #12
import Data.List (sort) -- GPS bench #16
import Data.Char (chr,ord) -- GPS bench #24
-- GPS bench #16:
#if __GLASGOW_HASKELL__ >= 710
import Data.List (isSubsequenceOf)
#else
isSubsequenceOf :: Eq a => [a] -> [a] -> Bool
isSubsequenceOf [] _ = True
isSubsequenceOf (_:_) [] = False
isSubsequenceOf (x:xs) (y:ys)
| x == y = xs `isSubsequenceOf` ys
| otherwise = (x:xs) `isSubsequenceOf` ys
#endif
gps1p :: Int -> Float -> Float
gps1p 0 1.0 = 1.0
gps1p 1 0.0 = 1.0
gps1p 1 1.0 = 2.0
gps1p 1 1.5 = 2.5
gps1g :: Int -> Float -> Float
gps1g x f = fromIntegral x + f
gps1c :: IO ()
gps1c = conjure "gps1" gps1p
[ fun "+" ((+) :: Float -> Float -> Float)
, fun "fromIntegral" (fromIntegral :: Int -> Float)
]
gps1c30p :: IO ()
gps1c30p = conjure "gps1" gps1p
[ con (0 :: Float)
, con (1 :: Float)
, con (1/2 :: Float)
, con (-1 :: Float)
, fun "+" ((+) :: Float -> Float -> Float)
, fun "*" ((*) :: Float -> Float -> Float)
, fun "-" ((-) :: Float -> Float -> Float)
, fun "abs" (abs :: Float -> Float)
, fun "negate" (negate :: Float -> Float)
, fun "id" (id :: Float -> Float)
, fun "fromIntegral" (fromIntegral :: Int -> Float)
, con (0 :: Int)
, con (1 :: Int)
, con (-1 :: Int)
, fun "+" ((+) :: Int -> Int -> Int)
, fun "*" ((*) :: Int -> Int -> Int)
, fun "-" ((-) :: Int -> Int -> Int)
, fun "div" (div :: Int -> Int -> Int)
, fun "mod" (mod :: Int -> Int -> Int)
, fun "^" ((^) :: Int -> Int -> Int)
, fun "abs" (abs :: Int -> Int)
, fun "negate" (negate :: Int -> Int)
, fun "id" (id :: Int -> Int)
, fun "round" (round :: Float -> Int)
, fun "truncate" (truncate :: Float -> Int)
, con False
, con True
, fun "&&" (&&)
, fun "||" (||)
, fun "not" not
]
gps2p :: Int -> Maybe String
gps2p 0 = Just "small"
gps2p 500 = Just "small"
gps2p 1000 = Nothing
gps2p 1500 = Nothing
gps2p 2000 = Just "large"
gps2p 2500 = Just "large"
gps2g :: Int -> Maybe String
gps2g n
| n < 1000 = Just "small"
| 2000 <= n = Just "large"
| otherwise = Nothing
gps2c :: IO ()
gps2c = conjure "gps2" gps2p
[ con "small"
, con "large"
, con (1000 :: Int)
, con (2000 :: Int)
, fun "Just" (Just :: String -> Maybe String)
, fun "Nothing" (Nothing :: Maybe String)
, fun "<=" ((<=) :: Int -> Int -> Bool)
, fun "<" ((<) :: Int -> Int -> Bool)
, iif (undefined :: Maybe String)
, maxTests 5040
, maxSize 30
]
gps3p :: Int -> Int -> Int -> [Int]
gps3p 0 9 1 = [0,1,2,3,4,5,6,7,8]
gps3p 2 9 2 = [2,4,6,8]
gps3g1 :: Int -> Int -> Int -> [Int]
gps3g1 start end step = enumFromThenTo start (step+start) (end-1)
gps3g2 :: Int -> Int -> Int -> [Int]
gps3g2 start end step = if start < end
then start : gps3g2 (start+step) end step
else []
gps3c :: IO ()
gps3c = do
conjure "gps3" gps3p
[ con (1 :: Int)
, fun "enumFromThenTo" ((\x y z -> take 720 $ enumFromThenTo x y z) :: Int -> Int -> Int -> [Int])
, fun "+" ((+) :: Int -> Int -> Int)
, fun "-" ((-) :: Int -> Int -> Int)
]
-- not possible, no recursive descent
conjure "gps3" gps3p
[ con ([] :: [Int])
, fun ":" ((:) :: Int -> [Int] -> [Int])
, fun "+" ((+) :: Int -> Int -> Int)
, fun "<" ((<) :: Int -> Int -> Bool)
, iif (undefined :: [Int])
, maxSize 8
]
gps4p :: String -> String -> String -> Bool
gps4p "" "a" "aa" = True
gps4p "aa" "a" "" = False
gps4p "a" "aa" "" = False
gps4p "a" "aa" "aaa" = True
gps4p "a" "aaa" "aa" = False
gps4p "aa" "a" "aaa" = False
gps4p "aa" "aaa" "a" = False
gps4p "aaa" "a" "aa" = False
gps4p "aaa" "aa" "a" = False
gps4g :: String -> String -> String -> Bool
gps4g s1 s2 s3 = length s1 < length s2 && length s2 < length s3
gps4c :: IO ()
gps4c = do
conjure "gps4" gps4p
[ fun "length" (length :: String -> Int)
, fun "<" ((<) :: Int -> Int -> Bool)
, fun "&&" (&&)
]
gps5p :: String -> String
gps5p "a" = "aa"
gps5p "b" = "bb"
gps5p " " = " "
gps5p "!" = "!!!"
gps5p "aa" = "aaaa"
gps5g :: String -> String
gps5g [] = []
gps5g (c:cs)
| isLetter c = c:c:gps5g cs
| c == '!' = c:c:c:gps5g cs
| otherwise = c:gps5g cs
gps5c :: IO ()
gps5c = conjure "gps5" gps5p -- can't find
[ con ""
, fun ":" ((:) :: Char -> String -> String)
, con '!'
, fun "==" ((==) :: Char -> Char -> Bool)
, fun "isLetter" (isLetter :: Char -> Bool)
, iif (undefined :: String -> String)
, maxSize 6
]
-- GPS Benchmark #6 -- Collatz/Hailstone numbers --
gps6p :: Int -> Int
gps6p 1 = 1
gps6p 2 = 2
gps6p 3 = 8
gps6p 4 = 3
gps6p 5 = 6
gps6p 6 = 9
gps6p 12 = 10
gps6p 60 = 20
gps6p 360 = 20
gps6g :: Int -> Int
gps6g = tnp1
where
tnp1 n | n <= 0 = undefined
tnp1 1 = 1 -- 1
tnp1 n = 1 + gps6g (if even n -- 7
then n `div` 2 -- 10
else 3*n + 1) -- 15
-- This one is out of reach performance wise:
-- Speculate hangs with this background.
-- Removing three or setting maxEqSize to 4 makes it unhang.
-- But a size of 15 or 17 is simplyl out of our reach.
gps6c :: IO ()
gps6c = conjure "gps6" gps6p
[ con (1 :: Int)
, con (2 :: Int)
, con (3 :: Int)
, fun "+" ((+) :: Int -> Int -> Int)
, fun "*" ((*) :: Int -> Int -> Int)
, fun "`div`" (div :: Int -> Int -> Int)
, fun "even" (even :: Int -> Bool)
, iif (undefined :: Int)
, maxSize 6
, maxEquationSize 3
]
-- GPS Benchmark #7 -- Replace Space with Newline (P 4.3)
gps7p :: String -> (String, Int)
gps7p "a" = ("a", 1)
gps7p "aa" = ("aa", 2)
gps7p "a a" = ("a\na", 2)
gps7p "a\na" = ("a\na", 2)
gps7g :: String -> (String, Int)
gps7g s = (init $ unlines $ words s, length (filter (not . isSpace) s))
gps7c :: IO ()
gps7c = conjure "gps7" gps7p
[ fun "," ((,) :: String -> Int -> (String, Int))
, fun "init" (init :: String -> String)
, fun "unlines" unlines
, fun "words" words
, fun "length" (length :: String -> Int)
, fun "filter" (filter :: (Char -> Bool) -> String -> String)
, fun "not" not
, fun "." ((.) :: (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool) -- cheat?
, fun "isSpace" (isSpace :: Char -> Bool)
]
-- GPS Benchmark #8 -- String Differences
gps8p :: String -> String -> [(Int, Char, Char)]
gps8p "a" "a" = []
gps8p "a" "b" = [(0,'a','b')]
gps8p "aa" "ab" = [(1,'a','b')]
gps8p "dealer" "dollar" = [(1,'e','o'), (2,'a','l'),(4,'e','a')]
gps8g :: String -> String -> [(Int, Char, Char)]
gps8g = diffs 0
where
diffs _ [] _ = []
diffs _ _ [] = []
diffs n (c:cs) (d:ds) = if c == d
then diffs (n+1) cs ds
else (n,c,d) : diffs (n+1) cs ds
-- out of reach as Conjure cannot invent helper functions
-- even if that would be solved,
-- I conjecture it would be out-of-reach performance-wise.
gps8c :: IO ()
gps8c = conjure "gps8" gps8p
[
]
-- GPS Benchmark #9 -- Even Squares
-- given an integer _n_, print all of the positive even perfect squares less
-- than _n_ on separate lines.
gps9p :: Int -> [Int]
gps9p 10 = [4]
gps9p 100 = [4,16,36,64]
gps9p 1000 = [4,16,36,64,100,144,196,256,324,400,484,576,676,784,900]
-- non-optimal performance, but does the job
-- gps9g :: Int -> [Int]
-- gps9g n = [x*x | x <- [1..n], x*x < n, even (x*x)]
gps9g :: Int -> [Int]
gps9g n = filter (n >) (filter even (map sq [1..n]))
where
sq = (^2)
gps9c :: IO ()
gps9c = conjure "gps9" gps9p
[ con (1 :: Int)
, fun "map" (map :: (Int -> Int) -> [Int] -> [Int])
, fun "filter" (filter :: (Int -> Bool) -> [Int] -> [Int])
, fun ".." (enumFromTo :: Int -> Int -> [Int])
, fun ">" ((>) :: Int -> Int -> Bool)
, fun "even" (even :: Int -> Bool)
, fun "sq" ((^2) :: Int -> Int) -- invented separately
, maxTests 60
]
-- GPS Benchmark #10 -- Wallis Pi
-- (quarter pi approximation)
-- 2 4 4 6 6 8 8
-- - x - x - x - x - x - x - x ...
-- 3 3 5 5 7 7 9
gps10p :: Int -> Rational
gps10p 1 = 2/3
gps10p 2 = 8/9
gps10p 3 = 32/45
gps10p 4 = 64/75
gps10p 5 = 128/175
gps10p 6 = 1024/1225
gps10g :: Int -> Rational
gps10g n = product $ take n $ iterate wallisNext (2/3)
wallisNextP :: Rational -> Rational
wallisNextP q
| q == 2/3 = 4/3
| q == 4/3 = 4/5
| q == 4/5 = 6/5
| q == 6/5 = 6/7
| q == 6/7 = 8/7
| q == 8/7 = 8/9
wallisNext :: Rational -> Rational
wallisNext q = if n < d
then (n+2) % d
else n % (d+2)
where
n = numerator q
d = denominator q
-- wallisNext (x % y) = (y + (y + 2)) % (x + (x + 2)) -- which simplifies to...
-- wallisNext (x % y) = (x + x * y) % (x + x * x) -- which simplifies to...
-- wallisNext (x % y) = (y + 1) % (x + 1) -- this correct version
gps10c :: IO ()
gps10c = do
conjure "wallisNext" wallisNextP
[ con (1 :: Integer)
, con (2 :: Integer)
, fun "+" ((+) :: Integer -> Integer -> Integer)
, fun "*" ((*) :: Integer -> Integer -> Integer)
, fun "%" ((%) :: Integer -> Integer -> Rational)
, fun "<" ((<) :: Integer -> Integer -> Bool)
-- , fun "numerator" (numerator :: Rational -> Integer)
-- , fun "denominator" (denominator :: Rational -> Integer)
, iif (undefined :: Rational)
]
-- simplified background
conjure "wallisNext" wallisNextP
[ con (0 :: Integer)
, con (1 :: Integer)
, fun "+" ((+) :: Integer -> Integer -> Integer)
, fun "*" ((*) :: Integer -> Integer -> Integer)
, fun "%" ((%) :: Integer -> Integer -> Rational)
]
conjure "gps10" gps10p
[ con (2 :: Integer)
, con (3 :: Integer)
, fun "%" ((%) :: Integer -> Integer -> Rational)
-- , con (2/3 :: Rational)
, fun "product" (product :: [Rational] -> Rational)
, fun "take" (take :: Int -> [Rational] -> [Rational])
, fun "iterate" ((\f -> take 720 . iterate f) :: (Rational -> Rational) -> Rational -> [Rational])
, fun "wallisNext" wallisNext
]
-- GPS Benchmark #11 -- Lengths Backwards
gps11p :: [String] -> [Int]
gps11p ["a"] = [1]
gps11p ["aa","a"] = [1,2]
gps11p ["a","aa"] = [2,1]
gps11p ["a","aa","aaa"] = [3,2,1]
gps11g :: [String] -> [Int]
gps11g = reverse . map length
gps11g2 :: [String] -> [Int]
gps11g2 [] = []
gps11g2 (s:ss) = gps11g2 ss ++ [length s]
gps11c :: IO ()
gps11c = do
conjure "gps11" gps11p
[ fun "reverse" (reverse :: [Int] -> [Int])
, fun "length" (length :: String -> Int)
, fun "map" (map :: (String -> Int) -> [String] -> [Int])
]
conjure "gps11" gps11p
[ con ([] :: [Int])
, fun ":" ((:) :: Int -> [Int] -> [Int])
, fun "++" ((++) :: [Int] -> [Int] -> [Int])
, fun "length" (length :: String -> Int)
]
-- GPS Benchmark #12 -- Last index or zero
gps12p :: [Int] -> Int
gps12p [0] = 0
gps12p [0,0] = 1
gps12p [0,1,0] = 2
gps12p [1,0,1] = 1
gps12p [0,1,0,1] = 2
gps12p [1,0,1,0] = 3
gps12g :: [Int] -> Int
gps12g xs = length xs - fromJust (findIndex (0==) (reverse xs)) - 1
gps12c :: IO ()
gps12c = do
conjure "gps12" gps12p
[ fun "length" (length :: [Int] -> Int)
, fun "reverse" (reverse :: [Int] -> [Int])
, fun "findIndex" (findIndex :: (Int -> Bool) -> [Int] -> Maybe Int)
, fun "fromJust" (fromJust :: Maybe Int -> Int)
, fun "-" ((-) :: Int -> Int -> Int)
, fun "==" ((==) :: Int -> Int -> Bool)
, con (0 :: Int)
, con (1 :: Int)
, maxSize 11
]
-- GPS Benchmark #13 -- Vector Average --
gps13p :: [Rational] -> Rational
gps13p [0,2] = 1
gps13p [1,3] = 2
gps13p [1,2,3] = 2 -- not hit, but nvm
gps13p [0,0,2,2] = 1
gps13g :: [Rational] -> Rational
gps13g qs = foldr (+) 0 qs / fromIntegral (length qs)
gps13c :: IO ()
gps13c = do
conjure "gps13" gps13p
[ fun "0" (0 :: Rational)
, fun "+" ((+) :: Rational -> Rational -> Rational)
, fun "/" ((/) :: Rational -> Rational -> Rational)
, fun "foldr" (foldr :: (Rational -> Rational -> Rational) -> Rational -> [Rational] -> Rational)
, fun "length" (length :: [Rational] -> Int)
, fun "fromIntegral" (fromIntegral :: Int -> Rational)
]
-- GPS Benchmark #14 -- Count Odds --
gps14p :: [Int] -> Int
gps14p [0,0] = 0
gps14p [1,3] = 2
gps14p [0,1,2] = 1
gps14g :: [Int] -> Int
gps14g xs = length (filter odd xs)
where
odd x = x `mod` 2 /= 0
gps14g2 :: [Int] -> Int
gps14g2 [] = 0
gps14g2 (x:xs) = if x `mod` 2 == 0
then gps14g2 xs
else 1 + gps14g2 xs
odd' :: Int -> Bool
odd' 0 = False
odd' 1 = True
odd' 2 = False
odd' 3 = True
odd' 4 = False
odd' 5 = True
gps14c :: IO ()
gps14c = do
conjure "odd" odd'
[ con (0 :: Int)
, con (1 :: Int)
, con (2 :: Int)
, fun "`mod`" (mod :: Int -> Int -> Int)
, fun "/=" ((/=) :: Int -> Int -> Bool)
]
conjure "gps14" gps14p
[ fun "odd" (odd :: Int -> Bool)
, fun "filter" (filter :: (Int -> Bool) -> [Int] -> [Int])
, fun "length" (length :: [Int] -> Int)
]
-- hah! I was expecting Conjure to use an if like above, but it was smarter:
-- gps14 [] = 0
-- gps14 (x:xs) = x `mod` 2 + gps14 xs
conjure "gps14" gps14p
[ con (0 :: Int)
, con (1 :: Int)
, con (2 :: Int)
, fun "+" ((+) :: Int -> Int -> Int)
, fun "`mod`" (mod :: Int -> Int -> Int)
, fun "==" ((==) :: Int -> Int -> Bool)
, iif (undefined :: Int)
]
-- GPS Benchmark #15 -- Mirror Image --
gps15p :: [Int] -> [Int] -> Bool
gps15p [0] [0] = True
gps15p [0,1] [1,0] = True
gps15p [0,1] [0,1] = False
gps15p [0,0,1] [1,0,0] = True
gps15p [0,0,1] [0,0,1] = False
gps15g :: [Int] -> [Int] -> Bool
gps15g xs ys = reverse xs == ys
gps15c :: IO ()
gps15c = do
conjure "gps15" gps15p
[ fun "==" ((==) :: [Int] -> [Int] -> Bool)
, fun "reverse" (reverse :: [Int] -> [Int])
]
-- GPS Benchmark #16 -- Super Anagrams --
gps16p :: String -> String -> Bool
gps16p "a" "aa" = True
gps16p "aa" "a" = False
gps16p "ab" "ba" = True
gps16p "ba" "ab" = True
gps16p "ab" "c" = False
gps16p "ab" "aba" = True
gps16g :: String -> String -> Bool
gps16g cs ds = sort cs `isSubsequenceOf` sort ds
gps16c :: IO ()
gps16c = do
conjure "gps16" gps16p
[ fun "`isSubsequenceOf`" (isSubsequenceOf :: String -> String -> Bool)
, fun "sort" (sort :: String -> String)
]
-- GPS Benchmark #17 -- Sum of Squares --
-- Given integer _n_, return the sum of squaring each integer in 1 to n
gps17p :: Int -> Int
gps17p 1 = 1
gps17p 2 = 5
gps17p 3 = 14
gps17p 4 = 30
gps17g :: Int -> Int
gps17g n = n * n + gps17g (n - 1)
gps17c :: IO ()
gps17c = conjure "gps17" gps17p
[ con (0 :: Int)
, con (1 :: Int)
, fun "+" ((+) :: Int -> Int -> Int)
, fun "*" ((*) :: Int -> Int -> Int)
, fun "-" ((-) :: Int -> Int -> Int)
]
-- GPS Benchmark #18 -- Vectors Summed --
-- zip with sum
gps18p :: [Int] -> [Int] -> [Int]
gps18p [0] [0] = [0]
gps18p [0,1] [0,1] = [0,2]
gps18p [1,0] [0,1] = [1,1]
gps18g :: [Int] -> [Int] -> [Int]
gps18g xs ys = zipWith (+) xs ys
gps18g' :: [Int] -> [Int] -> [Int]
gps18g' [] [] = []
gps18g' (x:xs) (y:ys) = x + y : gps18g' xs ys
gps18c :: IO ()
gps18c = do
conjure "gps18" gps18p
[ con ([] :: [Int])
, fun "+" ((+) :: Int -> Int -> Int)
, fun ":" ((:) :: Int -> [Int] -> [Int])
]
conjure "gps18" gps18p
[ fun "+" ((+) :: Int -> Int -> Int)
, fun "zipWith" (zipWith :: (Int -> Int -> Int) -> [Int] -> [Int] -> [Int])
]
-- GPS Benchmark #19 -- X-Word Lines --
gps19p :: Int -> String -> String
gps19p 1 "a a a" = "a\na\na\n"
gps19p 1 "a\na\na" = "a\na\na\n"
gps19p 2 "a a a" = "a a\na\n"
gps19g :: Int -> String -> String
gps19g x xs = unlines (map unwords (chunk x (words xs)))
chunk :: Int -> [String] -> [[String]]
chunk x [] = []
chunk x ss = take x ss : chunk x (drop x ss)
gps19c :: IO ()
gps19c = do
-- speculate takes too long
conjure "gps19" gps19p $ take 0
[ fun "words" (words :: String -> [String])
-- , fun "words" (lines :: String -> [String])
, fun "unwords" (unwords :: [String] -> String)
, fun "unlines" (unlines :: [String] -> String)
-- , fun "chunk" (chunk :: Int -> [String] -> [[String]])
-- , fun "map" (map :: ([String] -> String) -> [[String]] -> [String])
]
-- GPS Benchmark #20 -- Pig Latin --
gps20s :: (String -> String) -> Bool
gps20s pig = pig "hello world" == "ellohay orldway"
&& pig "a string" == "aay tringsay"
gps20g :: String -> String
gps20g = pig
pig :: String -> String
pig = unwords . map pig1 . words
pig1 :: String -> String
pig1 (c:cs) = if isVowel c
then (c:cs) ++ "ay"
else cs ++ (c:"ay")
pig1Spec :: (String -> String) -> Bool
pig1Spec pig1 = pig1 "hello" == "ellohay"
&& pig1 "world" == "orldway"
&& pig1 "string" == "tringsay"
&& pig1 "east" == "eastay"
isVowel :: Char -> Bool
isVowel 'a' = True
isVowel 'e' = True
isVowel 'i' = True
isVowel 'o' = True
isVowel 'u' = True
isVowel 'y' = True
isVowel _ = False
isVowel' :: Char -> Bool
isVowel' 'a' = True
isVowel' 'e' = True
isVowel' 'i' = True
isVowel' 'o' = True
isVowel' 'u' = True
isVowel' 'y' = True
isVowel' ' ' = False
isVowel' 'b' = False
isVowel' 'c' = False
isVowel' 'd' = False
isVowel' 'f' = False
isVowel' 'g' = False
gps20c :: IO ()
gps20c = do
conjure "isVowel" isVowel'
[ con 'a'
, con 'e'
, con 'i'
, con 'o'
, con 'u'
, con 'y'
, con True
, con False
]
conjureFromSpec "pig1" pig1Spec
[ con "ay"
, iif (undefined :: String)
, fun "isVowel" isVowel
, fun "++" ((++) :: String -> String -> String)
, fun ":" ((:) :: Char -> String -> String)
, target 50400
]
conjureFromSpec "gps20c" gps20s
[ fun "words" (words :: String -> [String])
, fun "unwords" (unwords :: [String] -> String)
, fun "map" (map :: (String -> String) -> [String] -> [String])
, fun "pig1" pig1
]
-- GPS Benchmark #21 -- Negative To Zero --
gps21p :: [Int] -> [Int]
gps21p [1] = [1]
gps21p [-1] = [0]
gps21p [1,-1] = [1,0]
gps21p [-1,1] = [0,1]
gps21g :: [Int] -> [Int]
gps21g [] = []
gps21g (x:xs) = (if x < 0 then 0 else x) : gps21g xs
gps21c :: IO ()
gps21c = conjure "gps21" gps21p
[ con ([] :: [Int])
, con (0 :: Int)
, fun ":" ((:) :: Int -> [Int] -> [Int])
, fun "<" ((<) :: Int -> Int -> Bool)
, iif (undefined :: Int)
]
-- GPS Benchmark #22 -- Scrabble Score --
gps22s :: (String -> Int) -> Bool
gps22s scrabble = scrabble "a" == 1
&& scrabble "hello" == 8
&& scrabble "world" == 9
&& scrabble "scrabble" == 14
gps22g :: String -> Int
gps22g = scrabble
scrabble :: String -> Int
scrabble s = foldr (+) 0 (map scrabble1 s)
scrabble1 :: Char -> Int
scrabble1 'd' = 2
scrabble1 'g' = 2
scrabble1 'b' = 3
scrabble1 'c' = 3
scrabble1 'm' = 3
scrabble1 'p' = 3
scrabble1 'f' = 4
scrabble1 'h' = 4
scrabble1 'v' = 4
scrabble1 'w' = 4
scrabble1 'y' = 4
scrabble1 'k' = 5
scrabble1 'j' = 8
scrabble1 'x' = 8
scrabble1 'q' = 10
scrabble1 'z' = 10
scrabble1 _ = 1 -- aeilnorstu
gps22c :: IO ()
gps22c = do
conjureFromSpec "gps22" gps22s
[ con (0 :: Int)
, fun "+" ((+) :: Int -> Int -> Int)
, fun "map" (map :: (Int -> Int) -> [Int] -> [Int])
, fun "scrabble1" scrabble1
]
-- GPS Benchmark #23 -- Word Stats --
gps23p :: String -> ([(Int,Int)], Int, Double)
gps23p = undefined
-- gps23p "" = ([], 0, 1.0/0.0)
gps23c :: IO ()
gps23c = do
conjure "gps23" gps23p []
-- GPS Benchmark #24 -- Checksum --
gps24p :: String -> Char
gps24p "a" = 'A'
gps24p "aa" = '"'
gps24p "a a" = 'B'
gps24p "b" = 'B'
gps24g :: String -> Char
gps24g s = chr (sum (map ord s) `mod` 64 + ord ' ')
gps24c :: IO ()
gps24c = conjure "gps24" gps24p
[ con ' '
, con (64 :: Int)
, fun "+" ((+) :: Int -> Int -> Int)
, fun "`mod`" (mod :: Int -> Int -> Int)
, fun "sum" (sum :: [Int] -> Int)
, fun "ord" ord
, fun "chr" chr
, fun "map" (map :: (Char -> Int) -> String -> [Int])
]
-- GPS Benchmark #25 -- Digits --
gps25p :: Int -> [Int]
gps25p 0 = [0]
gps25p 1 = [1]
gps25p 12 = [2,1]
gps25p (-21) = [1,-2]
gps25g :: Int -> [Int]
gps25g 0 = [0] -- 3
gps25g n = if abs n < 10 -- 8
then [n] -- 11
else abs (n `rem` 10) : gps25g (n `quot` 10) -- 20
-- out of reach performance-wise
gps25c :: IO ()
gps25c = conjure "gps25" gps25p $ take 0
[ con (0 :: Int)
, con (10 :: Int)
, con ([] :: [Int])
, fun ":" ((:) :: Int -> [Int] -> [Int])
, iif (undefined :: [Int])
, fun "abs" (abs :: Int -> Int)
, fun "<" ((<) :: Int -> Int -> Bool)
, fun "rem" (rem :: Int -> Int -> Int)
, fun "quot" (quot :: Int -> Int -> Int)
]
-- GPS Benchmark #26 -- Grade --
gps26p :: Int -> Int -> Int -> Int -> Int -> Char
gps26p 4 3 2 1 5 = 'A'
gps26p 4 3 2 1 4 = 'A'
gps26p 4 3 2 1 3 = 'B'
gps26p 4 3 2 1 2 = 'C'
gps26p 4 3 2 1 1 = 'D'
gps26p 4 3 2 1 0 = 'F'
gps26g :: Int -> Int -> Int -> Int -> Int -> Char
gps26g a b c d x
| x >= a = 'A'
| x >= b = 'B'
| x >= c = 'C'
| x >= d = 'D'
| otherwise = 'F'
-- out of reach performance-wise
gps26c :: IO ()
gps26c = conjure "gps26" gps26p
[ con 'A'
, con 'B'
, con 'C'
, con 'D'
, con 'F'
, iif (undefined :: Char)
, fun ">=" ((>=) :: Int -> Int -> Bool)
, maxSize 2
]
-- GPS Benchmark #27 -- Median --
gps27p :: Int -> Int -> Int -> Int
gps27p 0 1 2 = 1
gps27p 1 0 2 = 1
gps27p (-1) 1 0 = 0
gps27g :: Int -> Int -> Int -> Int
gps27g x y z
| y < x && x < z = x -- 8
| x < y && y < z = y -- 16
| otherwise = z -- 17
-- Conjure found a smaller implementation!
gps27c :: IO ()
gps27c = do
conjure "gps27" gps27p
[ fun "<" ((<) :: Int -> Int -> Bool)
, fun "&&" (&&)
, iif (undefined :: Int)
]
conjure "gps27b" gps27p
[ fun "min" (min :: Int -> Int -> Int)
, fun "max" (max :: Int -> Int -> Int)
]
-- GPS Benchmark #28 -- Smallest --
gps28p :: Int -> Int -> Int -> Int -> Int
gps28p 0 1 2 3 = 0
gps28p 3 2 1 0 = 0
gps28p 1 0 2 3 = 0
gps28p 3 2 0 1 = 0
gps28p 1 1 1 2 = 1
gps28c :: IO ()
gps28c = conjure "gps28" gps28p
[ fun "`min`" (min :: Int -> Int -> Int)
]
-- GPS Benchmark #29 -- Syllables --
gps29s :: (String -> Int) -> Bool
gps29s sys = sys "pub" == 1
&& sys "hello" == 2
&& sys "world" == 1
&& sys "string" == 1
&& sys "haskell" == 2
&& sys "photography" == 4
gps29g :: String -> Int
gps29g "" = 0
gps29g (c:cs) = if isVowel c
then 1 + gps29g cs
else gps29g cs
gps29c :: IO ()
gps29c = conjureFromSpec "gps29" gps29s
[ con (0 :: Int)
, con (1 :: Int)
, fun "+" ((+) :: Int->Int->Int)
, iif (undefined :: Int)
, fun "isVowel" isVowel
]
main :: IO ()
main = do
as <- getArgs
case as of
[] -> sequence_ gpss
(n:_) -> gpss !! (read n - 1)
gpss :: [IO ()]
gpss = [ gps1c
, gps2c
, gps3c
, gps4c
, gps5c
, gps6c
, gps7c
, gps8c
, gps9c
, gps10c
, gps11c
, gps12c
, gps13c
, gps14c
, gps15c
, gps16c
, gps17c
, gps18c
, gps19c
, gps20c
, gps21c
, gps22c
, gps23c
, gps24c
, gps25c
, gps26c
, gps27c
, gps28c
, gps29c
]