[Haskell-cafe] Client-extensible heterogeneous types (Duck-typed
variadic functions?)
Brandon Moore
brandon_m_moore at yahoo.com
Thu Oct 14 18:07:27 EDT 2010
> Thank you all for your contributions so far. Plenty of food for thought.
>
> I though I'd try to put it into practice and have a go at the motivating
>example I gave: essentially a EDSL for defining simple maths tests.
If you have a Python version that has other features you would like, you can
send that too.
> But it all goes pear shaped as soon as I try to cater for questions dealing
>with fractions, for example: Now the type system requires me to duplicate all
>the question-making utilities and give them different names. I tried to
>mitigate this by using type classes but got walloped by the No Monomorphism
>Restriction, and so on, and so forth. Wherever I turned, the type system was
>getting in the way.
NoMonomorphismRestriction is the one extension I used. I suppose I could have
replaced
def = beautiful combinators
by
def x = beautiful combinators x
Dealing with curried functions of varying arity is one thing that does tend to
be fairly annoying, but in this case addParam was possible. The rest was pretty
straightforward, mostly avoiding duplication by making more specific helpers
rather than more generic functions.
{-# LANGUAGE NoMonomorphismRestriction #-}
import System.IO (hFlush, stdout)
data Result = Correct | Improve String | Huh String | Incorrect String
deriving Show
data Question = Question { ask :: String
, answer :: String
, check :: String -> Result }
bool2result True = Correct
bool2result False = Incorrect ""
readCheckBy :: (Read a) => (a -> Bool) -> String -> Result
readCheckBy pred str =
case reads str of [(val,"")] -> bool2result (pred val)
_ -> Huh ""
readCheck :: (Read a, Eq a) => a -> String -> Result
readCheck v s = readCheckBy (==v) s
-- helpers
value val prompt = Question prompt (show val) (readCheck val)
infix2 op symbol a b = value (op a b) (unwords [show a, symbol, show b])
addParam :: (Show a) => (funTy -> String -> qty) -> (a -> funTy) -> String -> (a
-> qty)
addParam qmakr fun string v = qmakr (fun v) (string++" "++show v)
prefix1 = addParam value
prefix2 = addParam prefix1
prefix3 = addParam prefix2
-- question 'types'
addition = infix2 (+) "+"
subtraction = infix2 (-) "-"
multiplication = infix2 (*) "x"
power = infix2 (^) "^"
square = (flip power) 2
cube = (flip power) 3
square' = prefix1 (^2) "square"
pi1 = value pi "pi"
pi2 = Question "pi" (show pi) (readCheckBy (\v -> abs (pi - v) / pi < 0.0001))
questions = [ addition 1 2
, subtraction 3 2
, multiplication 4 5
, square 3
, cube 3
, square' 7
, value 3.14 "pi"
]
test :: Question -> IO ()
test q = do
putStr $ ask q ++ " = "
hFlush stdout
reply <- getLine
putStrLn $ show $ check q reply
main = mapM_ test questions
More information about the Haskell-Cafe
mailing list