4

So, I'm trying to learn Purescript by converting some Haskell code I had from the 99 Haskell Problems, and quickly got into a situation where I know how to solve it, but it is simply too ugly™. Here's the Haskell code for problems 10, 11 and 12; basically some RLE encode and decode functions:

-- Problem 10

rle :: Eq α => [α] -> [(Int, α)]
rle [] = []
rle (x:xs) = let (h, t) = span (== x) xs 
              in (length h + 1, x) : rle t

-- Problem 11

data RleItem α = Pair Int α | Single α deriving (Show)

encode :: Eq α => [α] -> [RleItem α]
encode = map unpack . rle 
   where unpack (1, x) = Single x
         unpack (y, x) = Pair y x

-- Problem 12

decode :: [RleItem α] -> [α]
decode = concatMap unroll
  where unroll (Pair y x) = replicate y x
        unroll (Single x) = [x] 

I quickly learned that:

  • There's no [] shorthand;
  • There's no (,) tuples;
  • We need to quantify polymorphic functions with an explicit forall;
  • No pattern matching with cons (:) operator for the Array type;
  • ...

So here's the question: what is the most idiomatic way to write the above solution in Purescript?

Hugo Sereno Ferreira
  • 8,600
  • 7
  • 46
  • 92

2 Answers2

6

There's no [] shorthand

In PureScript we explicitly call the type constructor List

There's no (,) tuples

In PureScript we either use the Tuple type, or another common pattern is to use records with descriptive names, like I did in my solution below.

We need to quantify polymorphic functions with an explicit forall

yes

No pattern matching with cons (:) operator for the Array type

We can pattern match on the List type with :. Pattern matching the head of an Array is almost never a good idea as it's very bad for performance.

I've translated your solution into PureScript using the points mentioned above. The example can also be tried and run at: http://try.purescript.org/?gist=f45651a7f4d134d466d575b1c4dfb614&backend=core

-- Problem 10

rle :: forall a. (Eq a) => List a -> List {repetitions :: Int, value :: a}
rle Nil = Nil
rle (x:xs) = case span (_ == x) xs of
  {init: h, rest: t} -> {repetitions: length h + 1, value: x} : rle t

-- Problem 11

data RleItem a = Pair Int a | Single a

encode :: forall a. Eq a => List a -> List (RleItem a)
encode = map unpack <<< rle 
   where 
    unpack = case _ of
      {repetitions: 1, value} -> Single value
      {repetitions, value} -> Pair repetitions value

-- Problem 12

decode :: forall a. List (RleItem a) -> List a
decode = concatMap unroll
  where unroll (Pair y x) = replicate y x
        unroll (Single x) = singleton x 
Christoph Hegemann
  • 1,434
  • 8
  • 13
1

This was my own answer so far (albeit not completely 1:1), though I don't expect to accept it:

data RleItem α = Pair Int α | Single α

encode :: forall α. (Eq α) => List α -> List (RleItem α)
encode Nil = Nil
encode p@(x:_) = let s = span ((==) x) p in
  pack (length s.init) : encode s.rest where
    pack 0 = Single x
    pack y = Pair y x

decode :: forall α. List (RleItem α) -> List α
decode = (=<<) unpack where
  unpack (Single x) = pure x
  unpack (Pair y x) = replicate y x
Hugo Sereno Ferreira
  • 8,600
  • 7
  • 46
  • 92