Allow use of function that takes in input as parameters instead of loop that parses standard input

I am somewhat new to CodinGame, and I think it is a really cool concept. But one thing that really turns me off is how unidiomatic the code base templates are, particularly when it comes to functional languages. In my opinion it would be much cleaner if there was an option where you could write a function that took in input as arguments as an alternative to the current loop structure.

For example Power of Thor could be converted from:

import System.IO
import Control.Monad

main :: IO ()
main = do
    hSetBuffering stdout NoBuffering -- DO NOT REMOVE

    -- Auto-generated code below aims at helping you parse
    -- the standard input according to the problem statement.
    -- ---
    -- Hint: You can use the debug stream to print initialTX and initialTY, if Thor seems not follow your orders.

    input_line <- getLine
    let input = words input_line
    let lightx = read (input!!0) :: Int -- the X position of the light of power
    let lighty = read (input!!1) :: Int -- the Y position of the light of power
    let initialtx = read (input!!2) :: Int -- Thor's starting X position
    let initialty = read (input!!3) :: Int -- Thor's starting Y position
    loop

loop :: IO ()
loop = do
    input_line <- getLine
    let remainingturns = read input_line :: Int -- The remaining amount of turns Thor can move. Do not remove this line.

    -- hPutStrLn stderr "Debug messages..."

    -- A single line providing the move to be made: N NE E SE S SW W or NW
    putStrLn "SE"

    loop

to:

powerOfThor :: Int -> Int -> Int -> Int -> Int -> String
powerOfThor lightX lightY thorX thorY remaining = "SE"

One difference is that in the second you get thorX and thorY instead of just the initial X and Y which you then have to keep incrementing in the original version. Which admittedly makes the challenge “easier” but IMO testing your ability to keep incrementing a variable isn’t very important.

The only other difference that I can see is that because you are not in the IO monad you have to use something like Debug.Trace for debugging, but that doesn’t seem like that much of an issue IMO. If IO is really that important you could also have something like:

powerOfThor :: Int -> Int -> Int -> Int -> Int -> IO String
powerOfThor lightX lightY thorX thorY remaining = return "SE"

For challenges with more input then putting a data structure or two at the top so that you don’t have too many arguments would also work just fine.

For those unfamiliar with Haskell the equivalent for Python would be:

def power_of_thor(light_x, light_y, thor_x, thor_y, remaining):
    return "SE"

Would love to hear feedback / explanations why it isn’t practical / possible. Because I know I would personally be really happy if this was implemented. Currently (for Haskell at least) I am probably just going to artificially convert each program to the functional method, but it would be nice to not have to do that for every problem / to get rid of the boilerplate that my temporary solution creates, it is also sometimes somewhat challenging to do so.

I should also note that I fully realize this would take a non-trivial amount of effort on the back end as you would have to import and call the submitted code rather than just run it and pass in standard input. This post is not meant to be a complaint or anything like that, but rather an attempt at persuading those running this cool site to at least consider the idea.

1 Like

I’ve posted a rather similar message some time ago. Like it seems to have disappear in the limbos, here is a copy of an improved template for Haskell.

Since the Onboarding challenge has changed, it is no more a valid solution (so play nicely Thor, there’s no need to strike my code!). If you pay attention to new challenge templates, you will see that CG is not deaf and actually has brought some improvements to their own templates.

It’s not perfect, but, beyond the mere fact that their staff cannot be proficient in all languages and their idiosyncrasies (I really like this word), the blame is partly on Haskell itself. Haskell could be very idiomatic (this one too) and even if one get quickly accustomed to things such as replicateM n (readThing <$> getLine), it could easily be offputting for newbies.

The problem remains that the actual templates in Haskell could be simple to understand, but still not very usable. I think that a template providing a pure function solve :: ParsedContextInput -> ParsedTurnInput -> FormattedOutput to implement would be a valuable enhancement.

1 Like

Thanks for your feedback, here are some explanations about how thinks work internally for us and why the provided code is ugly in some languages.

The current infrastructure requires a full source code that will be compiled and executed on our servers. We could ask the user to write their solution in a function that receives the input but we still need to add the ugly code that reads the input from stdin. It would be a lot of changes to modify that but we could maybe come with a client-side solution that would collapse the code that reads the input.

The reason why the code is bad for functional programming languages is mainly because we use a procedural language to describe how to read the input and that language is translated line by line in the 25 languages we currently support. Here’s an example of our language:

read n:int
read m:int
loop n read x:int y:int

The last reason is that no-one in our team is a functional programmer. So we know that the code is not perfect but we don’t know what would be better. We read users feedback with interest but it’s still not easy to know how to fix the thing.

This is not a problem, but the statement of a new puzzle :smiley_cat:. Just give the details about your generic language and let write some compiler! I just need to finish tweaking this damn pod racer engine before.

Do you have a formal specification of that language? Or some more examples?

I think I can write a better Haskell template based on the examples. Won’t be perfect, or close to the suggestion above, but will definitely look nicer.

For example, your

read n:int read m:int loop n read x:int y:int

would be translated roughly to

n <- fmap read getLine :: IO Int
m <- fmap read getLine :: IO Int
xys <- replicateM n $ fmap (map read . words) getLine :: IO [Int]

We will communicate about this soon because we want to allow contributors of community puzzles to write the code.

Thanks. Looking forward to it.

With knowledge of the specifications of your generic procedural language. I am sure we could make a compiler that would convert it into two sections of Haskell (or any other language) code. The first section stored internally on your servers and prepended to user code behind the scenes, and the second shown as a template for the user to edit.

I am by no means a Haskell expert, but I would be more than willing to help any other Haskell programmers make such a compiler.