[Haskell-cafe] Code critique - Was [Maybe Int] sans Nothings

michael rice nowgate at yahoo.com
Mon May 30 21:12:05 CEST 2011


Nice tool. I'll be using it a lot from now on, I'm sure. Thanks, Neil.
Michael

--- On Mon, 5/30/11, Neil Mitchell <ndmitchell at gmail.com> wrote:

From: Neil Mitchell <ndmitchell at gmail.com>
Subject: Re: [Haskell-cafe] Code critique - Was [Maybe Int] sans Nothings
To: "michael rice" <nowgate at yahoo.com>
Cc: "Haskell Cafe" <haskell-cafe at haskell.org>, "Alexander Solla" <alex.solla at gmail.com>
Date: Monday, May 30, 2011, 1:55 PM

Hi Michael,
You've used quite a few entirely redundant brackets. The tool HLint (http://community.haskell.org/~ndm/hlint) will tell you which ones.

Thanks, Neil

On Wed, May 25, 2011 at 12:09 AM, michael rice <nowgate at yahoo.com> wrote:

The input file: http://dl.dropbox.com/u/27842656/psalms

The Markov chain exercise from "The Practice of Programming", Kermighan/Pike. Sample runs at the end.

Michael
============================ 

import System.Environment(getArgs)import System.Randomimport Control.Applicativeimport Control.Monad.Reader
import Control.Monad.Stateimport Data.Maybeimport Data.Map
type Prefix = (String,String)type GeneratorState1 = State ((Map Prefix [String]),Prefix,[String])
type GeneratorState2 = StateT (Prefix,StdGen) (Reader (Map Prefix [String]))
non_word = "\n"
f key new old = new ++ old 
buildMap :: GeneratorState1 (Map Prefix [String])
buildMap = do (mp,(pfx1,pfx2),words) <- get              if (Prelude.null words)                then {-
 No more words. Return final map (adding non_word for final prefix). -}                  return (insertWithKey' f (pfx1,pfx2) [non_word] mp)                else do {- Add word to map at prefix & continue. -}
                  put (insertWithKey' f (pfx1,pfx2) [head words] mp, (pfx2,(head words)), tail words)                  buildMap
generate :: GeneratorState2 (Maybe String)
generate = do ((pfx1,pfx2),gen) <- get              mp <- ask              let suffixList = mp ! (pfx1,pfx2)              let (index,newGen) = randomR (0, (length suffixList)-1)
 gen              let word = suffixList !! index               if (word == non_word)                then                  return Nothing                else do
                  put ((pfx2,word),newGen)                  return (Just word)
rInt :: String -> IntrInt = read 
main = do (seed:nwords:_) <- (Prelude.map rInt) <$> getArgs
          contents <- getContents          putStrLn $ unwords $ catMaybes $ runReader (evalStateT (sequence $
 replicate nwords generate) ((non_word,non_word),mkStdGen seed))                                                     (evalState buildMap (singleton (non_word,non_word) [], (non_word,non_word), words contents))

{-[michael at hostname ~]$ ghc --make markov.hs[1 of 1] Compiling Main             ( markov.hs, markov.o )Linking markov ...[michael at hostname ~]$ cat psalms | ./markov 111 100
Blessed is the LORD, in thine own cause: remember how the foolish people have blasphemed thy name. In the courts of the righteous: The LORD taketh pleasure in the desert. And he led them with the wicked, and with the whole earth, is mount Zion, on the sides of thine only. O God, and was troubled: I complained, and my God. My
 times are in thy praise. Blessed be God, which is full of the LORD is good: for his wondrous works. Now also when I am small and despised: yet do I put my trust: how say ye to[michael at hostname ~]$ cat psalms | ./markov 666 100
Blessed is the LORD, and cried unto thee, Thy face, LORD, will I remember thee from the beginning: and every one that is weaned of his heart to any wicked transgressors. Selah. They return at evening: they make ready their arrow upon the people; and thou hast destroyed all them that fight against them that trust in thee: and let my tongue cleave to the heavens by his power for ever; and thy lovingkindnesses; for they have laid a snare before them: and that my ways were directed to keep thy word. Mine eyes fail while I have said that
[michael at hostname ~]$ 
--- On Tue,
 5/24/11, Alexander Solla <alex.solla at gmail.com> wrote:


From: Alexander Solla <alex.solla at gmail.com>
Subject: Re: [Haskell-cafe] [Maybe Int] sans Nothings
To: "Haskell Cafe" <haskell-cafe at haskell.org>

Date: Tuesday, May 24, 2011, 5:01 PM



> Personally, I find non-functional values without Eq instances to be

> degenerate.  So I really do not mind superfluous Eq constraints.  I

> would not hesitate to use filter ((/=) Nothing) in a function whose type

> has no free type variables.  It's just a bit of plumbing inside of a

> more complex function.



Sometimes it seems to be better to not allow Eq on Float and Double.

Since most algebraic laws do not hold for those types, it is more often

an error than an intention to compare two Float values. And how to

compare (IO a) values? 
Floats, Doubles, and IO are all "degenerate" types, for the reasons you outline.  (Admittedly, Float and Double have Eq instances, but invalid Eq semantics)  Notice how their value semantics each depend on the machine your runtime runs on, as opposed to merely the runtime.  Bottom is another one of these degenerate types, since comparisons on arbitrary values are undecidable.


Also, by thinking about function types, you often

get interesting use cases. Thus I would not assume too quickly that a

type will always be instantiated by types other than a function type.

Thus I would stick to (filter isJust) and use this consistently for

monomorphic and polymorphic types.


I am not suggesting (filter ((/=) Nothing)) /over/ (filter isJust).  Obviously, once one is aware of a  better tool, one should use it.  But I am suggesting that for simple cases which are unlikely to change in any substantive way, we should probably just use the tools we already know of, as opposed to searching for the "right" one.  Both might involve costs.  There is a cost involved in going to Google, thinking up a search term, finding that Data.Maybe has relevant functions, picking the right one.  It takes less time to write "filter ..." than to type "haskell removing nothing from list", for example.  When dealing with known unknowns, there is a balance to be made, and it is not easy. 


Michael's choice to ask the list imposed costs.  (Not that we mind, we're all volunteers, after all).  But it probably took 10 minutes to get the first reply.  He could have written a bit of code that worked correctly, given the context of his problem, in 20 seconds.  Then again, he probably worked on a different bit of code until somebody sent a solution, so we probably only have to account for the time spent in context switching, for everyone involved.




-----Inline Attachment Follows-----

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe at haskell.org

http://www.haskell.org/mailman/listinfo/haskell-cafe

_______________________________________________


Haskell-Cafe mailing list

Haskell-Cafe at haskell.org

http://www.haskell.org/mailman/listinfo/haskell-cafe




-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20110530/72918918/attachment.htm>


More information about the Haskell-Cafe mailing list