0

I'm new to Haskell and I'm trying to figure out how to add without having to use the '+' sign. I'm using Winhugs as a compiler.

Let's say, cookies = 10, chocolate = 5, cake = 20

if I enter,

cookies 1 chocolate 1

output should be,

15

here's what I have

cookies :: Int -> Int
cookies 1 = 10
cookies n = 10 + cookies (n-1)

chocolate :: Int -> Int
chocolate 1 = 5
chocolate n = 5 + chocolate (n-1)

i have to enter,

cookies 1 + chocolate 1

in order to get 15. Is there another way around this?

I also tried using recursive types but I still find it very confusing. I tried this one too but I can only add two items and I'd always have to input cookies:

cookies ::  Int -> (Int -> Int) -> Int -> Int 
cookies x item y = (x * 20) + item y

cake :: Int -> Int
cake 1 = 20
cake n = 20 + cake (n-1)

chocolate :: Int -> Int
chocolate 1 = 5
chocolate n = 5 + chocolate (n-1)

also, I cannot enter just cookies as it should always have another item with it.

cookies 1

ERROR - Cannot find "show" function for:

*** Expression : cookies 1

*** Of type : (Int -> Int) -> Int -> Int

I'm sorry for the very noob question. Thank you to everyone who can help!

** UPDATE ** I know I could use a different compiler but it's what's being taught in school and it's the compiler we need to use for our project as well :(

4
  • 1
    Winhugs is obsolete. Please consider using a more modern compiler, GHC, and for a more well-rounded experience, you could use Stack Commented Sep 8, 2017 at 12:19
  • i would but it's the compiler that we're being taught to use in school :( Commented Sep 8, 2017 at 12:34
  • 1
    @Mel that may be, but here you're clearly straying into territory that's not covered by school curriculum, and may quite possibly not be doable with Hugs at all. In fact it's debatable whether it makes any sense to do it, still... you should use GHC, and nobody at school can seriously mind you doing that. They just probably think Hugs is easier. Commented Sep 8, 2017 at 13:06
  • This is more like a domain-specific language (DSL) than a function. Commented Sep 8, 2017 at 14:01

3 Answers 3

6

I don't understand why you want all of this. What you're trying to implement is called variadic function. Haskell doesn't really support these, and I really don't believe it makes sense to use them for your application. What's wrong with cookies 1 + chocolate 2?

That said, the Haskell2010 / GHC-Haskell type system is sufficiently flexible to allow hacking together variadic functions:

{-# LANGUAGE TypeFamilies, FlexibleInstances #-}

class Crumbles c where
  crumble :: Int -> c
instance Crumbles Int where
  crumble = id
instance (f ~ (Int -> Int), i ~ Int, Crumbles c) => Crumbles (f -> i -> c) where
  crumble acc f i = crumble $ f i + acc

Now you can do

cookies :: Crumbles c => Int -> c
cookies n = crumble $ n*10

chocolate :: Crumbles c => Int -> c
chocolate n = crumble $ n*5

goodies :: [Int]
goodies = [ cookies 1  -- 10
          , cookies 1 chocolate 1   -- 15
          , cookies 1 chocolate 1 cookies 100000  -- 1000015
          ]

main :: IO ()
main = print goodies

...giving [10,15,1000015].

I don't know if Hugs supports the TypeFamilies extension that's needed for the equational constraints f ~ (Int -> Int) and i ~ Int.


What I suspect the task is going for is something entirely different, namely, how to implement cookies :: Int -> Int without using either addition nor multiplication, i.e. without writing *10 nor 10 + cookies (n-1). The answer they probably want should use only the succ and pred functions (which are equivalent to +1 and -1, respectively).

Sign up to request clarification or add additional context in comments.

7 Comments

Hi! thank you for your response! "What's wrong with cookies 1 + chocolate 2" My professor's very specific about stuff and he wants us to do cookies 1 chocolate 2 instead :( i tried what you typed out but hugs unfortunately does not support that extension. Thank you for trying to help!
Ugh. That's an absurd requirement! But well, now you have one crippled solution that allows the exact syntax cookies 1 chocolate 1 (but nothing else) and also works in Hugs, and one ridiculous typeclass-hackery solution that allows anything of the form crumble a crumble b ... crumble ω. Let them choose...
@Mel That looks as a very unusual requirement. Double check the assignment, since it seems unreasonable to require that cookies 1 chacolate 2 works. Maybe the professor forgot the +? If possible I'd write to the professor and ask to confirm that. From a teaching point of view, it seems a very pointless exercise, since its solution requires to abuse the typeclass machinery, which is not something that should be taught.
@chi yeah i checked again and that's what he's requiring. i dont think it's a mistake since he gave 5 examples. All of which had no operator
@Mel Are you sure your professor is asking for the Haskell term cookies 1 chocolate 2 to work, and not asking you to write a program which accepts cookies 1 chocolate 2 as input? The latter is significantly easier (and significantly closer to the kind of assignment I could imagine giving to beginners).
|
2

Don't try to write functions named cookies and chocolate which, when typed into the hugs interpreter, behave that way.

Instead, try to write an IO action which accepts input, parses it, and does the appropriate computation. You may like the interact function, which takes a function on Strings and runs it on things the user types:

interact :: (String -> String) -> IO ()

For example, with runhaskell (which is very similar to hugs), the following code:

main = interact $ \s ->
    "What is your name?\n" ++
    filter (/='\n') s ++ ", nice to meet you!\n"

produces the following interaction:

% runhaskell test.hs
What is your name?
Daniel
Daniel, nice to meet you!

Note that I pressed the EOF button after typing Daniel and pressing enter; on Linux this is ctrl-d but I believe on Windows it is ctrl-z. Note also that nowhere in the code is there a definition for Daniel -- this Daniel that I typed in is not a Haskell term, but rather is input read by running the Haskell term main.

Comments

1

Like Daniel Wagner, I suspect this question is misguided. I find it hard to believe that the assignment is asking for functions cookies and chocolate that can be combined in this way. Rather, it’s probably asking for a function calculate :: String -> Int which accepts the string "cookies 1 chocolate 2", parses it, and returns the result.

For that, a solution is pretty simple—so I won’t give it away. Break the problem down into small steps like these:

  • "cookies 1 chocolate 2"

  • ["cookies", "1", "chocolate", "2"]

  • [("cookies", 1), ("chocolate", 2)]

  • [10, 10]

  • 20

Write a function for each step, and a main that asks for input and calls these functions to calculate the final result. Bonus points if you consider how to use Maybe or Either to handle errors in the input, such as an unknown item, a non-numeric quantity, a missing quantity, &c.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.