I'm learning Haskell, and I've finally gotten around to coding up some Haskell. This code passed my tests.
This code takes a line from standard in which tells it how many cases it's going to have (1 to 5), and for each case, it takes a line telling it how many pairs (max of 100) of x's and y's it will get (integers from 0 to 500), and it should print YES
if x to y is a function, and NO
otherwise.
e.g. with a file called input
:
2
2
1 1
2 1
2
1 1
1 2
The following command should work like this:
$ runhaskell main.hs < input
YES
NO
In my source code the only difference is I have two blank lines for style instead of one between each group of code. My main.hs
:
import Control.Monad (replicateM_, replicateM, forM)
import Data.String (words)
main = do
times <- readLn :: IO Int
replicateM_ times input_is_a_function
input_is_a_function = do
n_inputs <- readLn :: IO Int
inputs <- replicateM n_inputs getLine
if (null inputs) || (is_function inputs) then
putStrLn "YES"
else
putStrLn "NO"
is_function inputs = is_func ([map read $ words i | i <- inputs] :: [[Int]])
is_func (x_y : rest)
| rest == [] = True
| otherwise = (no_other_y x_y rest) && (is_func rest)
no_other_y [x1, y1] rest
| rest == [] = True
| otherwise = this_y_ok && (no_other_y [x1, y1] (tail rest))
where
this_y_ok = not (x_is_target && y_not_equal)
x_is_target = x1 == head (head rest)
y_not_equal = y1 /= ((head rest) !! 1)
-- if target is false, y is ok.
-- if target is True, y must be equal
The algorithm starts with the first pair of x and y, and does a search for a repetition of x and determines if it matches y or not. Any found x with a mismatch on y should stop the algorithm.
I come from a Python background, so I tend to use snake-case and idioms I am more immediately familiar with (list comprehensions FTW!), but I want to learn idiomatic Haskell.
I also value readability. I could probably have better names. Perhaps more typing would improve readability, but I tried to take as much advantage of Hindley-Milner type inference as I could.
Please address efficiency, typing, style, naming, or any other important issues you identify.
On my workflow: I've been using a basic ghc (7.10.3) from the Ubuntu repos with a test file and that command mentioned above.
Is there a better approach? e.g. a way to watch the file and run tests as I code and save? In Haskell?