Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

/prog/ challenge [HASKELL]

Name: Anonymous 2008-05-09 13:15

Use the loeb function:
loeb :: Functor a => a (a x -> x) -> a x
loeb x = fmap (\a -> a (loeb x)) x


To implement a basic spreadsheet processor. The processor should accept input of the form:
|##|A        |B    |C   |D       |
|01|(* B1 C1)|2    |3   |(* A1 2)|

The output from this example should be:
|##|A      |B    |C   |D     |
|01|6      |2    |3   |12    |

Cells may contain number literals, references to other cells of the form <letter><number>, or function applications of the form (<function> *<args>).

Name: Anonymous 2008-05-09 13:19

And what if I don't know Haskell?

Name: Anonymous 2008-05-09 13:25

This is too hard. Can't you do a challenge were you have to calculate the Fibonacci numbers.

Name: Anonymous 2008-05-09 14:11

import qualified Data.Map as M

data Cell a = Num a
             | Ref (Char, Int)
        | Fun (a -> a -> a) (Cell a) (Cell a)

type Spreadsheet a = M.Map (Char, Int) a


eval :: Cell a -> Spreadsheet a -> a
eval (Num x) s = x
eval (Ref l) s = s M.! l
eval (Fun f x y) s = f (eval x s) (eval y s)


loeb :: Functor a => a (a x -> x) -> a x
loeb x = fmap (\a -> a (loeb x)) x


process :: Spreadsheet (Cell a) -> Spreadsheet a
process = loeb . fmap eval

test = M.fromList [(('A', 1), Fun (*) (Ref ('B', 1)) (Ref ('C', 1))),
                   (('B', 1), Num 2),
                   (('C', 1), Num 3),
                   (('D', 1), Fun (*) (Ref ('A', 1)) (Num 2))]


main = print (process test)


Parsing and printing left as an exercise for the reader.

Name: Anonymous 2008-05-09 16:44

OP here, I've got parsing and evaluation, but no writing yet; I'm about as lazy as my language!

module Main where
import Data.Array
import Control.Monad
import Data.List
import System.IO
import Control.Arrow
import qualified Text.ParserCombinators.Parsec as P

(.:) = (.) . (.)

split :: (Eq a) => a -> [a] -> [[a]]
split _ [] = [[]]
split delim (x:xs) | x == delim = [] : rest
                   | otherwise = (x : head rest) : tail rest
                     where rest = split delim xs

remove :: (Eq a) => a -> [a] -> [a]
remove x (y:ys) | x == y = remove x ys
                | otherwise = y : remove x ys
remove x [] = []

loeb :: Functor a => a (a x -> x) -> a x
loeb x = fmap (\a -> a (loeb x)) x

type Cell = (Int, Char)
type Symbol = String
type Number = Double
data Expr = LitE Number
          | RefE Cell
          | AppE Symbol [Expr] deriving (Show)

type Prim = [Number] -> Number
prims :: [(Symbol, Prim)]
prims = map (second binop) $
  [("+", (+)), ("-", (-)), ("*", (*)), ("/", (/))]
  where binop prim [x, y] = prim x y

parseExpr :: (Monad m) => String -> m Expr
parseExpr x = case P.parse (P.between pad pad expr) [] x of
                Left exc -> fail $ show exc
                Right x' -> return x'
  where expr = P.choice [app, ref, lit]
        lit = do first <- (P.try $ sequence [P.char '-', P.digit]) P.<|>
                            liftM return P.digit
                 rest <- P.many $ P.digit P.<|> P.char '.'
                 return $ LitE $ read (first ++ rest)
        ref = let column = P.oneOf ['A'..'Z']
                  row = liftM read $ P.many1 P.digit
              in liftM2 (RefE .: flip (,)) column row
        app = P.between (P.char '(' >> pad) (pad >> P.char ')') $
                liftM2 AppE symbol $ pad >> P.sepBy1 expr pad1
        [pad, pad1] = map ($ P.oneOf " \t") [P.many, P.many1]
        symbol = let special = P.oneOf "!#$%&|*+-/:<.=>?@^_~"
                     first = P.letter P.<|> special
                     rest = P.choice [P.letter, P.digit, special]
                 in liftM2 (:) first (P.many rest)

type Sheet a = Array Cell a

eval :: Expr -> Sheet Number -> Number
eval (LitE lit) _ = lit
eval (RefE ref) sheet = sheet ! ref
eval (AppE fun args) sheet =
  case lookup fun prims of
    (Just f) -> f args'
    Nothing -> error $ "eval: unknown builtin '" ++ fun ++ "'"
  where args' = map (`eval` sheet) args

readSheet :: Handle -> IO (Sheet Expr)
readSheet handle =
  do header <- getCells
     let columns = map (head . remove ' ') (tail header)
     (`unless` fail "readSheet: incorrect header format") $
       nub (header !! 0) == "#" && (and $ zipWith (==) ['A'..'Z'] columns)
     let loop n rows =
           do isEOF <- hIsEOF handle
              if isEOF then return $ reverse rows
                else do (n':row) <- getCells
                        when (n /= read n') $
                          fail "readSheet: row number out of sync"
                        mapM parseExpr row >>= loop (n + 1) . (:rows)
     rows <- loop 1 []
     return $ listArray ((1, 'A'), (length rows, last columns)) $ concat rows
  where getCells = liftM (remove [] . split '|') $ hGetLine handle

writeSheet :: Handle -> Sheet Number -> IO ()
writeSheet handle sheet = return () -- TODO

process :: Sheet Expr -> Sheet Number
process = loeb . fmap eval

Name: Anonymous 2008-05-09 18:26

wait. whats a functor?

Name: Anonymous 2008-05-09 18:26

what does the loeb function do in words.

Name: Anonymous 2008-05-09 18:47

>>7
Haskellers never describe anything.  I'm still waiting for them to tell me what a fucking Monad does without resorting to whimsical metaphor.

Name: Anonymous 2008-05-09 18:50

>>8
Warm, fuzzy things

Name: Anonymous 2008-05-09 19:12

>>5
Jesus shit, this looks like an ass factory exploded. Fucking Haskell mouthbreathers.

Name: Anonymous 2008-05-09 19:47

>>10
ass factory
Haskell

You must mean an ass monad. Ass factory explosions are Java code.

Name: Anonymous 2008-05-09 19:59

Monads are a fancy way of composing functions ('binding' them).
A functor is something you can map over, for instance a list.
Loeb takes a functor of functions, applies them to the result of loebing that functor of functions, and returns the functor of results.

Name: Anonymous 2008-05-09 20:16

>>13
functor my functoring functor

Name: Anonymous 2008-05-09 20:48

>>5
I usually rewrite the "tits operator" as .: too!

Name: Anonymous 2008-05-09 22:57

The amount of awesome condensed into Haskell code is too awesome for mere C programmers to comprehend.

Name: Anonymous 2008-05-10 18:16

(o)(o)

Name: Anonymous 2008-05-10 18:46

>>14
I rewrite it as °°

Name: Anonymous 2008-05-10 18:53

Would anyone tell me what the hell does .|. do?

Name: Anonymous 2008-05-10 18:55

>>15
it's fucking trivial in C, it's not a good example of loeb either

Name: Anonymous 2008-05-10 18:56

Would anyone tell me what the hell does 8==D do?

Name: Anonymous 2008-05-10 18:59

Name: Anonymous 2008-05-10 19:01

Would anyone tell me what the hell does (°v°) do ?

Name: Anonymous 2008-05-10 19:02

Would anyone tell me what the hell does /(º_º)\ do?

Name: Anonymous 2008-05-10 20:08

Would anyone tell me what the hell does ( ゚ ヮ゚) do?

Name: Anonymous 2008-05-10 22:56

>>19
In C you would have to do dependency analysis (a graph problem) to determine the order in which to evaluate cells. In Haskell, you let the compiler do that for you by using loeb. Which is awesome.
Also, I'd like to see a parser/evaluator written in C that is as expressive and concise as the Haskell solution.
SO GO READ K&R, I'LL BE HAVING SEX WITH MY CUTE HASKELL THE DOG.

Name: Anonymous 2008-05-11 1:10

>>25
In Haskell, the compiler thinks for you. You don't need to think yourself.

Name: Anonymous 2008-05-11 10:06


            ?
     ___/|
 ?   \o_O| . o O ( how can you explain loeb in "words" ? )
      \  |        
     f | | ?
     |_| |


>Loeb takes a functor of functions, applies them to the result of loebing that functor of functions, and returns the functor of results.

that's basically it, it's a literal translation of the code (heh, i wonder if you could machine-translate haskell :)). but if these words and concepts don't mean anything to you ("functor"?), it won't make things any clearer.

if you want to understand what loeb is all about you'll need more background knowledge (types, you need to know *all* about haskell's type system). here's a thread i started earlier that probably gave rise to this: http://dis.4chan.org/read/prog/1210284504/1- , it contains some more information, but probably not enough so you could get it.

Name: Anonymous 2008-05-11 10:26

>>27
What's a functor?

Name: Anonymous 2008-05-11 10:26

>>28
nvm just googled.
loeb is not that complicated really

Name: Anonymous 2008-05-11 10:50

>>29
It is. Link to the illuminating website please?

Name: Anonymous 2008-05-11 10:53

Name: Anonymous 2008-05-11 13:01

>>29,30
As with any Haskell concept, understanding it is just a matter of getting past all the intellectual masturbation on the part of the tutorial writer.

Loeb permits a set of functions to depend on each other's results in whatever arrangement they need...excluding circular dependencies of course.  Each function is given a reference to the whole (unsolved) result set, and when the function tries to read an element of that set, Haskell will recursively solve that function, cache its value, and return it.  As a base case, at least one function must ignore its argument.

If you've done any Haskell you've probably exploited this behavior plenty of times.  Loeb is just a generalization of it.

(Disclaimer: This is just going by what I've read of it on /prog/.)

Name: Anonymous 2008-05-11 13:05

>>32
This does not explain what a functor is.

Name: Anonymous 2008-05-11 13:05

>>33
Wikipedia does.

Name: Anonymous 2008-05-11 13:10

>>34
This is true.

Name: Anonymous 2008-05-11 14:11

Name: Anonymous 2008-05-11 14:11

Name: Anonymous 2008-05-11 14:11

Name: Anonymous 2008-05-11 14:12

Name: Anonymous 2008-05-11 14:12


Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List