Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Dec 13th, 2006, 6:50 PM   #11
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
Haskell introduces a number of things that dilute its purity. My view on this is that such things tend to occur when something moves from the theoretical or academic realm to a position of practical usage. Reality and utility intrude, or the subject remains, predominantly, an instructive, but largely ignored, concept. I personally, am more of a pragmatist than an idealist. Differences, of course, are what make horse races.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Old Dec 13th, 2006, 7:25 PM   #12
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 642
Rep Power: 4 Jessehk is on a distinguished road
Quote:
Originally Posted by DaWei View Post
I personally, am more of a pragmatist than an idealist.s.
I'd like to think I'm the same way. I think that the language itself suffers from a practical standpoint because they tried to make it too "pure". I think making anything practical of any size would be very difficult.

Ocaml is pretty neat in that regard (functional, but impure), but I wish it had certain features like function composition and lazy evaluation built-in.
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!
Jessehk is offline   Reply With Quote
Old Dec 14th, 2006, 3:41 AM   #13
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
Quote:
Originally Posted by DaWei View Post
Haskell introduces a number of things that dilute its purity.
I'm curious as to what you mean by this.
Quote:
Originally Posted by Jessehk
I think that the language itself suffers from a practical standpoint because they tried to make it too "pure". I think making anything practical of any size would be very difficult.
I'm not so sure about this. Some Haskell functions can be complicated to understand, but they are very concise, so you have less lines of code to figure out. Also, whilst they are complex, one would expect that a skilled Haskell programmer would have less trouble understanding them than I do, because frequently the cause of my misunderstandings stem from being unfamiliar with a particular function.

The main thing Haskell appears to lack, is a way of grouping together diverse pieces of data in a way they can be easily accessed. In other languages, objects or structs handle this, though I'm not sure how Haskell handles it. Possibly there's some way of using the type system to achieve the same effect?

Aside from that, I can't think of any practical difficulties using Haskell.
Arevos is offline   Reply With Quote
Old Dec 14th, 2006, 9:19 AM   #14
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
To me, anything that introduces side-effects is introducing an impurity to the fundamental paradigm. You may disagree. I'm also not saying that it's necessarily bad. I'm very, very new to the language, but I don't see it as having the capability to solve a lot of real-world problems in an effective way. This means that one either distorts the paradigm, or devises ways to merge other paradigms, with each being a contributor from its strengths.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Old Dec 14th, 2006, 12:22 PM   #15
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
Quote:
Originally Posted by DaWei View Post
To me, anything that introduces side-effects is introducing an impurity to the fundamental paradigm.
True, and any functional language wishing to interact with our Universe in any significant fashion will have to invoke side effects.

That said, Haskell never deals with side effects explicitly. Instead, it uses monads to handle them implicitly, preserving the functional paradigm. For instance, the putStrLn function is defined as being of the type:
String -> IO ()
In order words, it takes in a string as an argument, and returns an IO () value. One can use monads to string commands like this together in a sequence, allowing one to execute commands in order. The IO monad itself relies on black magic behind the scenes to invoke side effects, but externally it behaves in an entirely functional manner.
Arevos is offline   Reply With Quote
Old Dec 14th, 2006, 1:35 PM   #16
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
I think we just agreed .
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Old Dec 14th, 2006, 1:49 PM   #17
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
Quote:
Originally Posted by DaWei View Post
I think we just agreed .
I guess I was just pointing out that Haskell is about as pure a functional language as is possible to get and still remain practical. Most functional languages have the concept of side-effect functions, whilst Haskell abstracts all side effects into a black-magic data structure, leaving Haskell functions side-effect free, at least in principle.

Or, in a nutshell, Haskell has the minimum possible impurities a functional language can realistically have.

Edit I should add that I'm not disagreeing with you, DaWei, just drawing attention to a point of interest

Last edited by Arevos; Dec 14th, 2006 at 2:31 PM.
Arevos is offline   Reply With Quote
Old May 29th, 2007, 11:26 PM   #18
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 642
Rep Power: 4 Jessehk is on a distinguished road
In case anyone is interested, here is an updated Cards module. This one includes a State Monad Transformer (or something). I'm starting to dislike monads...

Cards.hs
-- Written by Jesse H-K
-- Monday, May 28, 2007

module Cards (
    Card(..),
    Face(),
    Suit(),
    Deck(),
    fullDeck,
    fullDeckWithJokers,
    dealCard,
    dealCards,
    printDeck
) where

import Data.List (delete)
import System.Random
import System.IO
import Control.Monad.State

data Card = Card Face Suit
          | Joker
          deriving Eq
          
instance Show Card where
    show (Card f s) = (show f) ++ " of " ++ (show s)
    show Joker      = "Joker"
    
instance Ord Card where
    compare (Card f s) (Card f' s') = compare f f'
    compare Joker (Card _ _) = GT
    compare Joker Joker      = EQ
    compare (Card _ _) Joker = LT
    
data Suit = Hearts
          | Clubs
          | Spades
          | Diamonds
          deriving (Show, Eq)
          
suits :: [Suit]
suits = [Hearts, Diamonds, Clubs, Spades]

data Face = Two
          | Three
          | Four
          | Five
          | Six
          | Seven
          | Eight
          | Nine
          | Ten
          | Jack
          | Queen
          | King
          | Ace
          deriving (Eq, Ord, Show)
          
faces :: [Face]
faces = [Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace]
    
type Deck = [Card]

fullDeck :: Deck
fullDeck = [Card f s | s <- suits, f <- faces]

fullDeckWithJokers :: Deck
fullDeckWithJokers = fullDeck ++ [Joker, Joker]

randCard :: Deck -> IO (Card, Deck)
randCard cards = do
    n <- randomRIO (0 :: Int, length cards - 1)
    let card = cards !! n
    return $ (card, delete card cards)

dealCard :: StateT Deck IO Card
dealCard = do
    d <- get
    (c, d') <- lift $ randCard d
    put d'
    return c

dealCards :: Int -> StateT Deck IO [Card]
dealCards n = replicateM n dealCard

printDeck :: Deck -> IO ()
printDeck = mapM_ print

example Main.hs
module Main where

import Control.Monad.State
import Data.List (sort)
import System

import Cards

getNumberCards :: IO Int
getNumberCards = do
    args <- getArgs >>= (mapM readIO)
    return $ head args

main :: IO ()
main = do
    n <- getNumberCards
    
    (cards, deck) <- runStateT (dealCards n) fullDeckWithJokers
    printDeck $ sort cards
    putStrLn $ (show $ length deck) ++ " cards remaining in deck."

Example usage:
$ ghc --make Main
[1 of 2] Compiling Cards            ( Cards.hs, Cards.o )
[2 of 2] Compiling Main             ( Main.hs, Main.o )
Linking Main ...
$ ./Main 3
Seven of Spades
Jack of Clubs
King of Diamonds
51 cards remaining in deck.
$ ./Main 5
Six of Diamonds
Seven of Diamonds
Eight of Diamonds
Eight of Clubs
Nine of Spades
49 cards remaining in deck.
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!
Jessehk is offline   Reply With Quote
Old May 30th, 2007, 3:01 PM   #19
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
Would you mind giving an explanation of what the monad transformation code is doing, Jessehk? I'm a little familiar with monad transformers, and I can see you're using a state monad to keep track of the state of the deck (I think), but I'm a little unsure of the details, and would be very grateful to read your explanation of it.
Arevos is offline   Reply With Quote
Old May 30th, 2007, 4:13 PM   #20
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 642
Rep Power: 4 Jessehk is on a distinguished road
Quote:
Originally Posted by Arevos View Post
Would you mind giving an explanation of what the monad transformation code is doing, Jessehk? I'm a little familiar with monad transformers, and I can see you're using a state monad to keep track of the state of the deck (I think), but I'm a little unsure of the details, and would be very grateful to read your explanation of it.
Sure, though I'm not very clear on the details myself.

So, I assume that everything is clear up to the randCard function.
randCard :: Deck -> IO (Card, Deck)
randCard cards = do
    n <- randomRIO (0 :: Int, length cards - 1)
    let card = cards !! n
    return $ (card, delete card cards)

This is basically a helper function that takes the current state (ie, the deck of cards from which to choose a card), and returns a random Card in addition to the new state (ie, the deck without the card).

Moving on:
dealCard :: StateT Deck IO Card
dealCard = do
    d <- get
    (c, d') <- lift $ randCard d
    put d'
    return c

The function definition indicates that this returns a StateT Deck IO Card. What this basically means (if I understand it correctly ), is that this function returns a computation that takes a state, and returns an IO Card.
Basically, it's a nested monad.

So, line by line:
d <- get

This line gets the current state, which is in this case, the current deck. The reason this works is not entirely clear to me, but essentially, but I'm pretty sure it has to do with the bind operator (>>=) and translation of the do notation. I suspect (and hope) that knowing the why in this case is not very important (I sort of know, but it's difficult to explain especially because there are gaps in my knowledge).

In any case, d now contains the current state of the deck.

(c, d') <- lift $ randCard d

Ok, this is the hardest part.
we know that randCard takes a deck and returns an IO action (Card, Deck).
The lift function takes a monad and returns that monad wrapped up in another.

lift :: (MonadTrans t, Monad m) => ma -> t m a

In our case, we know randCard d returns IO (Card, Deck). So lift encases it in the StateT monad. With that done, the do notation allows the easy abstraction of simply assigning the new state (Deck) to d' and the new card (IO Card) to c. Here's the thing I don't understand.
I don't get why (c, d') <- StateT Deck IO (Card, Deck) actually works. It's kind of bothering me, and I'm probably going to go on #haskell on Freenode later to ask. They're amazingly helpful.

Moving on...
put d'

We're now replacing the state in the monad with the new state. Basically, the deck is being updated.

return c

This basically means to encase the card (IO Card) in the StateT monad containing the updated deck, and return it.

Well, there you go. I tried, and I failed. It's one of the things I dislike about Haskell -- it can be bloody confusing.
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!
Jessehk is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 10:16 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC