Week #6 Challenge: Haskell

  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • Last »

57 Replies - 11321 Views - Last Post: 01 June 2010 - 06:46 AM

#1 skyhawk133  Icon User is offline

  • Head DIC Head
  • member icon

Reputation: 1868
  • View blog
  • Posts: 20,280
  • Joined: 17-March 01

Week #6 Challenge: Haskell

Post icon  Posted 08 February 2010 - 09:39 AM

Posted Image Week #6: Discover Haskell

Prize Challenge - This week we'll draw a random person that completes the challenge for a $50 Amazon Gift Card!

Challenge submitted by Raynes.

Posted Image

CHALLENGE: Write a desktop calculator in Haskell. It's a scalable application that you can take as far as you like. If you want, you can add variables, and by the time you've added tail recursion, you're turing complete. You can go simple, and just write a simple command-line calculator that does as much as you want it to do. You don't need to learn much of Haskell to write this. If you don't want to write a calculator, you're welcome to write something else. Just Have Fun

INTRODUCING THE LANGUAGE/TECHNOLOGY: It is hard to really introduce Haskell in few words. Haskell is a compiled, advanced purely functional programming language that has been around for over 20 years. Haskell is of the most popular functional programming languages. In Haskell, there are no side effects. There is no 'lets modify that global variable!'. There is no global state. Haskell is pure, and does I/O via the IO monad, which you will learn about fairly early. You don't even have to understand or know what Monads are to use the IO monad, and you can do this challenge with no knowledge of monads. Haskell is strongly and statically type, and the type system actually helps you, rather than gets in your way. Because Haskell is pure, and due to the power of it's type system, it makes it easy to write large, complex, and stable code. It's impossible for there to be a type error in your code at runtime. Code written in Haskell is more likely to work correctly if it compiles than in other languages.

Haskell isn't as hard as people make it out to be. When people say that you have to forget OOP and such to learn Haskell, they mean that you cannot try to learn Haskell and assume that OOP is the only way to do things, or try to write OOP code in Haskell. Haskell is easy to learn if you open your mind, and take yourself back to the beginning. The time before you knew other languages. Your previous knowledge will help you, and as long as your OOP assumptions are left behind, it will not hinder you. Haskell is amazingly fun, and one of the most elegant languages you will ever code in. There are a lot of cool things in Haskell that will blow your mind. Even if you don't decide to use Haskell for personal projects or anything more than this challenge, just writing a little code in Haskell will benefit you. I think once you've used Haskell, you'll want to know more.

More introduction materials can be found here:
http://haskell.org/h...ki/Introduction

IDEAS:
  • One you become more familiar with Haskell, turn your calculator into a turing complete language.
  • Add a GUI to your calculator using WxHaskell or gtk2hs (and Glade, the GUI builder if you like that sort of thing).
  • If a calculator doesn't appeal to you, write something else! Anything else! Just have fun!
RESOURCES:
My resource thread should definitely come in handy here: http://www.dreaminco...topic144577.htm

I especially recommend that you read through LYAH (Learn You A Haskell) if you're new to the language, and then if you want more, you can start reading Real World Haskell. You can find links to all of this and more in the thread I linked. There is a Functional Programming forum that Skyhawk created partially at my suggestion during my first few days on this site.

It's one of the reasons I like this site so much. It's here: http://www.dreaminco...topic144577.htm. I and a couple other people answer questions in there, though I'm probably the most frequent. If you have any questions, you can ask them there. There are also a few snippets in the Other Language snippet section, but I doubt it's enough to help anybody.

There is also a list of Haskell resources worth checking out:
http://web.cecs.pdx....skellLinks.html
(Provided by Portland State University)

Of course, it is always a good idea to check out the original developer site for tips and guides:
http://www.haskell.org/




HOW TO GET STARTED:
You're going to want to get Haskell via the Haskell Platform, a standard Haskell distribution for all systems. It comes with useful libraries, and stuff you need to install Haskell libraries from Cabal and such. Not to mention, the flagship Haskell compiler, GHC. It's insanely simple to install regardless of what system you use. There is even a Windows installer. You can find the link to the Haskell Platform to the resource thread I linked in resources.

After you've installed Haskell, you'll probably want to use Emacs or Vim to code in it. Of course, you can use any text editor, but you wont get the most out of Haskell unless you use Emacs or Vim. There is also an IDE for Haskell written in Haskell called Leksah. I hear it's pretty good at this stage. There is a bit of information about various editors, including relevant links in the resource thread.

Once you've installed Haskell, you can fire up a terminal and type 'ghci' to get the Haskell 'REPL' running. This is probably the most useful thing you will ever use. You can type in expressions and have them evaluated immediately. Once you have GHCi running, type this in:
putStrLn "Hello, DiC!"


Have fun!

Is This A Good Question/Topic? 3
  • +

Replies To: Week #6 Challenge: Haskell

#2 programble  Icon User is offline

  • (cons :dic :head)

Reputation: 49
  • View blog
  • Posts: 1,315
  • Joined: 21-February 09

Re: Week #6 Challenge: Haskell

Posted 08 February 2010 - 10:26 AM

This is an implementation of an encryption algorithm called SEAD that I came up with. SEAD stands for "Simple Encryption Algorithm, Duh". SEAD involved 2 steps: first, the input data and the key data are bitwise XOR'ed, then the result is substituted (each value is incremented) by the data length. Functions are provided to use Strings as input, which are converted into Bytes before being passed to the actual encryption functions. Not sure how great this code is...
module Sead
( encrypt
, encryptString
, decrypt
, decryptString
, toInts
, toString
) where

--imports--
import Data.Char
import Data.Bits

-- | Converts String/[Char] to [Int]
toInts :: String -> [Int]
toInts x = map ord x

-- | Converts [Int] to String/[Char]
toString :: [Int] -> String
toString x = map chr x

-- | XORs two [Int] together
xors :: Bits a => [a] -> [a] -> [a]
xors x y = zipWith xor x y

-- | Pad list to length by cycling
padrep :: Int -> [a] -> [a]
padrep x ys = take x . cycle $ ys

-- | Substitute by length
sublen :: [Int] -> [Int]
sublen xs = let l = length xs in
            map (+l) xs

-- | Substitute by the negated length
unsublen :: [Int] -> [Int]
unsublen xs = let l = negate . length $ xs in
              map (+l) xs

-- | Encrypt a String using SEAD
encryptString :: String -> String -> String
encryptString s k = let sd = toInts s
                        kd = toInts k
                        en = encrypt sd kd
                    in toString en

-- | Encrypt using SEAD
encrypt :: [Int] -> [Int] -> [Int]
encrypt d k = let pk = padrep (length d) k
                  xord = xors d pk
              in sublen xord

-- | Decrypt a String using SEAD
decryptString :: String -> String -> String
decryptString s k = let sd = toInts s
                        kd = toInts k
                        de = decrypt sd kd
                    in toString de

-- | Decrypt using SEAD
decrypt :: [Int] -> [Int] -> [Int]
decrypt d k = let pk = padrep (length d) k
                  unsub = unsublen d
              in xors unsub pk


Was This Post Helpful? 1
  • +
  • -

#3 Raynes  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 611
  • View blog
  • Posts: 2,815
  • Joined: 05-January 09

Re: Week #6 Challenge: Haskell

Posted 08 February 2010 - 10:40 AM

module Main where

parseInput :: [String] -> Double
parseInput (n1:op:n2:_)
    | op == "+" = num1 + num2
    | op == "*" = num1 * num2
    | op == "-" = num1 - num2
    | op == "/" = num1 / num2
    where num1 = (read n1 :: Double)
          num2 = (read n2 :: Double)

main = do
  putStrLn "Enter one number, an operator, and another number.\n"
  input <- getLine
  if input == "quit"
   then return ()
   else do
     putStrLn $ "Result is: " ++ show (parseInput (words input))
     main



This is a very naive and error prone command-line calculator I just threw together. Might help a few people.
Was This Post Helpful? 4
  • +
  • -

#4 Metropoler  Icon User is offline

  • D.I.C Head

Reputation: 2
  • View blog
  • Posts: 78
  • Joined: 29-December 09

Re: Week #6 Challenge: Haskell

Posted 08 February 2010 - 12:29 PM

I have never heard of it but I am very excited :)

I think it's too much new stuff to create a calculator within a week. For me it's a completely new area. It looks quite interesting but very challenging, too. Hopefully I will find a free spot to learn it 0_0

Thanks for all the links and the introduction.
And a big thanks to you Ranyes. The code is very helpful to get an impression of the language!
Was This Post Helpful? 0
  • +
  • -

#5 Raynes  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 611
  • View blog
  • Posts: 2,815
  • Joined: 05-January 09

Re: Week #6 Challenge: Haskell

Posted 08 February 2010 - 12:44 PM

No problem. My example doesn't do Haskell justice at all though. :)

Calculators are pretty easy, as my example shows. I choose this application because it's super-scalable. You can make it as difficult or simple as you like, either way, it's a submission. :P
Was This Post Helpful? 0
  • +
  • -

#6 erik.price  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 485
  • View blog
  • Posts: 2,690
  • Joined: 18-December 08

Re: Week #6 Challenge: Haskell

Posted 08 February 2010 - 01:30 PM

Neat, I was planning on learning Haskell in December, but never got around to it. Hopefully this challenge will change that :)
Was This Post Helpful? 0
  • +
  • -

#7 dorknexus  Icon User is offline

  • or something bad...real bad.
  • member icon

Reputation: 1255
  • View blog
  • Posts: 4,618
  • Joined: 02-May 04

Re: Week #6 Challenge: Haskell

Posted 08 February 2010 - 06:54 PM

I'm actually looking forward to this one. I've already been looking into haskell a little bit and it seems pretty cool thus far.
Was This Post Helpful? 0
  • +
  • -

#8 programble  Icon User is offline

  • (cons :dic :head)

Reputation: 49
  • View blog
  • Posts: 1,315
  • Joined: 21-February 09

Re: Week #6 Challenge: Haskell

Posted 09 February 2010 - 02:27 PM

Haskell seemed cool until I got to IO, then I barfed.
Was This Post Helpful? 0
  • +
  • -

#9 erik.price  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 485
  • View blog
  • Posts: 2,690
  • Joined: 18-December 08

Re: Week #6 Challenge: Haskell

Posted 09 February 2010 - 09:40 PM

Here's FizzBuzz, because Haskell's syntax still makes no sense to me :P (but I'm working on it!)
fizzBuzz n
	| n `mod` 15 == 0 = "FizzBuzz"
	| n `mod` 5 == 0 = "Buzz"
	| n `mod` 3 == 0 = "Fizz"
	| otherwise = show n 

showFizz xs = map printBuzz xs
	where printBuzz n = show (fizzBuzz n )




I relied heavily on the documentation and Real World Haskell for the syntax, so I'm not sure how correct it is. It works, it just prints out an ugly list of strings:
["\"FizzBuzz\"","\"1\"","\"2\"","\"Fizz\"","\"4\"","\"Buzz\"","\"Fizz\"","\"7\"","\"8\"","\"Fizz\"","\"Buzz\"","\"11\"","\"Fizz\"","\"13\"","\"14\"","\"FizzBuzz\"","\"16\"","\"17\"","\"Fizz\"","\"19\"","\"Buzz\"","\"Fizz\"","\"22\"","\"23\"","\"Fizz\"","\"Buzz\"","\"26\"","\"Fizz\"","\"28\"","\"29\"","\"FizzBuzz\"","\"31\"","\"32\"","\"Fizz\"","\"34\"","\"Buzz\"","\"Fizz\"","\"37\"","\"38\"","\"Fizz\"","\"Buzz\"","\"41\"","\"Fizz\"","\"43\"","\"44\"","\"FizzBuzz\"","\"46\"","\"47\"","\"Fizz\"","\"49\"","\"Buzz\"","\"Fizz\"","\"52\"","\"53\"","\"Fizz\"","\"Buzz\"","\"56\"","\"Fizz\"","\"58\"","\"59\"","\"FizzBuzz\"","\"61\"","\"62\"","\"Fizz\"","\"64\"","\"Buzz\"","\"Fizz\"","\"67\"","\"68\"","\"Fizz\"","\"Buzz\"","\"71\"","\"Fizz\"","\"73\"","\"74\"","\"FizzBuzz\"","\"76\"","\"77\"","\"Fizz\"","\"79\"","\"Buzz\"","\"Fizz\"","\"82\"","\"83\"","\"Fizz\"","\"Buzz\"","\"86\"","\"Fizz\"","\"88\"","\"89\"","\"FizzBuzz\"","\"91\"","\"92\"","\"Fizz\"","\"94\"","\"Buzz\"","\"Fizz\"","\"97\"","\"98\"","\"Fizz\"","\"Buzz\""]


Any ideas how to fix that?


Also, I'll try to submit some actual snippets later ;)
Was This Post Helpful? 0
  • +
  • -

#10 carltech  Icon User is offline

  • What did you call me?
  • member icon

Reputation: 28
  • View blog
  • Posts: 997
  • Joined: 19-October 07

Re: Week #6 Challenge: Haskell

Posted 10 February 2010 - 01:04 AM

It's already the middle of the week and I just read the challange...

I'll have to come up with something, Haskell is new to me.
Was This Post Helpful? 0
  • +
  • -

#11 Raynes  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 611
  • View blog
  • Posts: 2,815
  • Joined: 05-January 09

Re: Week #6 Challenge: Haskell

Posted 10 February 2010 - 03:31 PM

View Posterik.price, on 09 February 2010 - 08:40 PM, said:

Here's FizzBuzz, because Haskell's syntax still makes no sense to me :P (but I'm working on it!)
fizzBuzz n
	| n `mod` 15 == 0 = "FizzBuzz"
	| n `mod` 5 == 0 = "Buzz"
	| n `mod` 3 == 0 = "Fizz"
	| otherwise = show n 

showFizz xs = map printBuzz xs
	where printBuzz n = show (fizzBuzz n )




I relied heavily on the documentation and Real World Haskell for the syntax, so I'm not sure how correct it is. It works, it just prints out an ugly list of strings:
["\"FizzBuzz\"","\"1\"","\"2\"","\"Fizz\"","\"4\"","\"Buzz\"","\"Fizz\"","\"7\"","\"8\"","\"Fizz\"","\"Buzz\"","\"11\"","\"Fizz\"","\"13\"","\"14\"","\"FizzBuzz\"","\"16\"","\"17\"","\"Fizz\"","\"19\"","\"Buzz\"","\"Fizz\"","\"22\"","\"23\"","\"Fizz\"","\"Buzz\"","\"26\"","\"Fizz\"","\"28\"","\"29\"","\"FizzBuzz\"","\"31\"","\"32\"","\"Fizz\"","\"34\"","\"Buzz\"","\"Fizz\"","\"37\"","\"38\"","\"Fizz\"","\"Buzz\"","\"41\"","\"Fizz\"","\"43\"","\"44\"","\"FizzBuzz\"","\"46\"","\"47\"","\"Fizz\"","\"49\"","\"Buzz\"","\"Fizz\"","\"52\"","\"53\"","\"Fizz\"","\"Buzz\"","\"56\"","\"Fizz\"","\"58\"","\"59\"","\"FizzBuzz\"","\"61\"","\"62\"","\"Fizz\"","\"64\"","\"Buzz\"","\"Fizz\"","\"67\"","\"68\"","\"Fizz\"","\"Buzz\"","\"71\"","\"Fizz\"","\"73\"","\"74\"","\"FizzBuzz\"","\"76\"","\"77\"","\"Fizz\"","\"79\"","\"Buzz\"","\"Fizz\"","\"82\"","\"83\"","\"Fizz\"","\"Buzz\"","\"86\"","\"Fizz\"","\"88\"","\"89\"","\"FizzBuzz\"","\"91\"","\"92\"","\"Fizz\"","\"94\"","\"Buzz\"","\"Fizz\"","\"97\"","\"98\"","\"Fizz\"","\"Buzz\""]


Any ideas how to fix that?


Also, I'll try to submit some actual snippets later ;)


fizzBuzz n
        | n `mod` 15 == 0 = "FizzBuzz"
        | n `mod` 5 == 0 = "Buzz"
        | n `mod` 3 == 0 = "Fizz"
        | otherwise = show n

showFizz xs = mapM_ printBuzz xs
        where printBuzz n = putStrLn $ fizzBuzz n



You were calling show on the result of fizzBuzz n twice. fizzBuzz always returns a string, because even if it's a number, you're already calling show on it. You were calling show on it AGAIN which make a string representation of a string, and that's what was making it ugly. I've also fixed it so that it actually prints each element of the result list now as well.
Was This Post Helpful? 1
  • +
  • -

#12 erik.price  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 485
  • View blog
  • Posts: 2,690
  • Joined: 18-December 08

Re: Week #6 Challenge: Haskell

Posted 10 February 2010 - 04:58 PM

Ah, thanks Raynes. I had absolutely no idea what I was doing :P
Was This Post Helpful? 0
  • +
  • -

#13 Paul-  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 61
  • View blog
  • Posts: 260
  • Joined: 11-December 09

Re: Week #6 Challenge: Haskell

Posted 10 February 2010 - 08:47 PM

This was a challenge, no kidding. First, my openSUSE, although having several GB of software, it has no Haskell. I had to compile from sources, including installing missing libraries: what a pain. Then I struggled with the Haskell syntax...

Anyway, here is my attempt at a calculator. It is still missing the part where it reads the input in a meaningful way, like parsing a string. But once an expression is loaded into an "Exp" type, the calculator can display and evaluate it.

module Main where

data Exp = Const Double
     | Add Exp Exp
     | Sub Exp Exp
     | Mul Exp Exp
     | Div Exp Exp

showExp :: Exp -> String
showExp (Const a) = show a
showExp (Add e1 e2) = "(" ++ showExp e1 ++ " + " ++ showExp e2 ++ ")"
showExp (Sub e1 e2) = "(" ++ showExp e1 ++ " - " ++ showExp e2 ++ ")"
showExp (Mul e1 e2) = "(" ++ showExp e1 ++ "*" ++ showExp e2 ++ ")"
showExp (Div e1 e2) = "(" ++ showExp e1 ++ "/" ++ showExp e2 ++ ")"

evalExp :: Exp -> Double
evalExp (Const a) = a
evalExp (Add e1 e2) = (evalExp e1) + (evalExp e2)
evalExp (Sub e1 e2) = (evalExp e1) - (evalExp e2)
evalExp (Mul e1 e2) = (evalExp e1) * (evalExp e2)
evalExp (Div e1 e2) = (evalExp e1) / (evalExp e2)

main = do
     let exp1 = (Mul (Const 2) (Add (Const 5) (Const 3.5)))
     putStrLn $ showExp exp1
     putStrLn $ show (evalExp exp1)
     let exp2 = (Add (Const 5) (Sub (Const 1) (Const 7)))
     putStrLn $ showExp exp2
     putStrLn $ show (evalExp exp2)



Extending on the above calculator, here is one that works with complex numbers.

It would still be nice to parse a string, to let the user input an expression, but I don't know how to do it. Perhaps somebody else can help with that.

module Main where

data Complex = Complex Double Double

data Exp = Const Complex
     | Add Exp Exp
     | Sub Exp Exp
     | Mul Exp Exp
     | Div Exp Exp

showComplex :: Complex -> String
showComplex (Complex r i) = "[" ++ show r ++ "," ++ show i ++ "i]"

getReal :: Complex -> Double
getReal (Complex r _) = r

getImag :: Complex -> Double
getImag (Complex _ i) = i

showExp :: Exp -> String
showExp (Const a) = showComplex a
showExp (Add e1 e2) = "(" ++ showExp e1 ++ " + " ++ showExp e2 ++ ")"
showExp (Sub e1 e2) = "(" ++ showExp e1 ++ " - " ++ showExp e2 ++ ")"
showExp (Mul e1 e2) = "(" ++ showExp e1 ++ "*" ++ showExp e2 ++ ")"
showExp (Div e1 e2) = "(" ++ showExp e1 ++ "/" ++ showExp e2 ++ ")"

evalExp :: Exp -> Complex
evalExp (Const a) = a
evalExp (Add e1 e2) = 
	let c1 = evalExp e1
	    c2 = evalExp e2
	in Complex (getReal c1 + getReal c2)
	   (getImag c1 + getImag c2)
evalExp (Sub e1 e2) = 
	let c1 = evalExp e1
	    c2 = evalExp e2
	in Complex (getReal c1 - getReal c2)
	   (getImag c1 - getImag c2)
evalExp (Mul e1 e2) = 
	let c1 = evalExp e1
	    c2 = evalExp e2
	    r1 = getReal c1
	    i1 = getImag c1
	    r2 = getReal c2
	    i2 = getImag c2
	in Complex (r1*r2 - i1*i2) (r1*i2 + i1*r2)
evalExp (Div e1 e2) = 
	let c1 = evalExp e1
	    c2 = evalExp e2
	    r1 = getReal c1
	    i1 = getImag c1
	    r2 = getReal c2
	    i2 = getImag c2
	    d = r2*r2 + i2*i2
	in Complex ((r1*r2 + i1*i2)/d) ((i1*r2-r1*i2)/d)

main = do
     let exp1 = Sub (Add (Const (Complex 2 3)) (Const (Complex 3 3)))
     	      (Const (Complex 2 1))
     putStrLn $ showExp exp1
     putStrLn $ showComplex (evalExp exp1)

     let exp2 = Div (Const (Complex 1 0)) (Const (Complex 1 (-1)))
     putStrLn $ showExp exp2
     putStrLn $ showComplex (evalExp exp2)

     let exp3 = Mul (Const (evalExp exp2)) (Const (Complex 1 (-1)))
     putStrLn $ showExp exp3
     putStrLn $ showComplex (evalExp exp3)


This post has been edited by Paul-: 10 February 2010 - 08:48 PM

Was This Post Helpful? 0
  • +
  • -

#14 njovin  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 6
  • Joined: 31-January 10

Re: Week #6 Challenge: Haskell

Posted 10 February 2010 - 10:36 PM

I was going to build a nice flight computer with a nifty interface but I completely choked on all the IO stuff. I might keep working at it but this language is a trip for me.

As it turned out, here's a stupidly easy function that takes a true course, magnetic course, true air speed, and ground speed and calculates the wind speed.

{- Convert degrees to radians, accepts a course and heading, returns a list with the same, converted -}
deg2rad cr hd = [(pi/180) * cr,(pi/180) * hd]

{- Calculate the wind speed  using TAS, GS, head, course -}
windSpeed tas gs head course = 
	sqrt(
	((tas-gs)^2) + 4 * tas * gs * (
	sin((
	deg2rad course head !! 0 - deg2rad course head !! 1
	)/2)
	)^2
	)


Was This Post Helpful? 0
  • +
  • -

#15 MentalFloss  Icon User is offline

  • "ADDICTED"[2:5]
  • member icon

Reputation: 526
  • View blog
  • Posts: 1,397
  • Joined: 02-September 09

Re: Week #6 Challenge: Haskell

Posted 10 February 2010 - 10:57 PM

I have never looked into haskell or seen any source or anything.
So, thanks for the helpful links. I now intend to participate in this one.

As it stands, the source code I've seen so far must be the closest thing to magical incantations I've ever seen regarding my understanding of programming.
Was This Post Helpful? 0
  • +
  • -

  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • Last »