Purescript中的惯用Haskell RLE

时间:2017-03-08 23:56:45

标签: haskell purescript

所以,我试图通过转换99 Haskell Problems中的一些Haskell代码来学习Purescript,并很快陷入了我知道如何解决它的情况,但它只是太丑了™的。这是问题10,11和12的Haskell代码;基本上是一些RLE编码和解码功能:

-- 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] 

我很快就了解到:

  • 没有[]简写;
  • 没有(,)元组;
  • 我们需要使用明确的forall;
  • 来量化多态函数
  • cons (:)类型的Array运算符无格式匹配;
  • ...

所以这就是问题:在Purescript 中编写上述解决方案的最惯用方法是什么?

2 个答案:

答案 0 :(得分:5)

  

没有[]简写

在PureScript中,我们显式调用类型构造函数List

  

没有(,)元组

在PureScript中,我们使用Tuple类型,或者另一种常见模式是使用具有描述性名称的记录,就像我在下面的解决方案中所做的那样。

  

我们需要使用显式的forall量化多态函数

  

没有与数组类型的cons(:)运算符匹配的模式

我们可以将List类型与:进行模式匹配。匹配Array头部的模式几乎不是一个好主意,因为它对性能非常不利。

我已使用上述各点将您的解决方案翻译成PureScript。该示例也可以在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 

答案 1 :(得分:1)

到目前为止,这是我自己的答案(虽然不完全是1:1),但我不希望接受它:

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