![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#11 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
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 |
|
|
|
|
|
#12 |
|
The Oblivious One
Join Date: May 2005
Location: Ontario, Canada
Posts: 642
Rep Power: 4
![]() |
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! |
|
|
|
|
|
#13 | |
|
Programming Guru
![]() Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5
![]() |
I'm curious as to what you mean by this.
Quote:
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. |
|
|
|
|
|
|
#14 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
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 |
|
|
|
|
|
#15 | |
|
Programming Guru
![]() Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5
![]() |
Quote:
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 () |
|
|
|
|
|
|
#16 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
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 |
|
|
|
|
|
#17 |
|
Programming Guru
![]() Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5
![]() |
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. |
|
|
|
|
|
#18 |
|
The Oblivious One
Join Date: May 2005
Location: Ontario, Canada
Posts: 642
Rep Power: 4
![]() |
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_ printexample 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! |
|
|
|
|
|
#19 |
|
Programming Guru
![]() Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5
![]() |
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.
|
|
|
|
|
|
#20 | |
|
The Oblivious One
Join Date: May 2005
Location: Ontario, Canada
Posts: 642
Rep Power: 4
![]() |
Quote:
![]() 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 cThe 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! |
|
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|