Skip to main content
edited tags; edited title
Link
200_success
  • 144.2k
  • 22
  • 188
  • 473

Haskell Determining whether (x, somey) points in the input, some analysis, some output constitute a function

Source Link
Aaron Hall
  • 1.6k
  • 14
  • 35

Haskell, some input, some analysis, some output

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?