惯用的haskell代码

时间:2013-06-13 14:39:50

标签: haskell

给定一个列表lst和一个数字n,以下代码输出一个列表,其中包含n个给定列表中lst个不同的元素。

rndsel :: (Eq a, RandomGen g) => [a] -> g -> Int -> [a]
rndsel lst _ 0 = []
rndsel lst g n = schar:(rndsel rem g (n-1))
  where schar = lst !! index
        index = head $ randomRs (0, ll-1) g
        ll = length lst
        rem = delete schar lst

我想知道是否有任何方法可以改进这段代码的可读性,口才以及是否可以使其更具惯用性的haskell代码?

1 个答案:

答案 0 :(得分:5)

  1. 为了与列表中的其他函数更好地组合,最好将输入列表参数移动到最后位置,即:

      

    g - > Int - > [a] - > [α]

    通过这种方式,您可以像这样使用您的功能:

    nub . rndsel g n . sort $ someList
    
  2. 使用“n”参数更改“generator”的顺序也更自然,因为“n”似乎是最具动态性的:

      

    Int - > g - > [a] - > [α]

  3. !!函数是部分函数,​​如果您为其提供大于列表大小的索引,则会向您显示运行时错误。最近,使用部分功能被认为是一种不好的做法。

  4. head功能也是部分功能。

  5. List不是基于索引的结构,并且按索引访问它的元素(!!函数)具有O(n)复杂度,这是非常无效的。

  6. 你的函数的问题域很容易分成另外两个更简单的问题:改组和取一部分洗牌结果。那里有很多很好的改组算法实现,Fisher Yates似乎最适合你的情况。它有以下签名:

    shuffle :: RandomGen g => g -> [a] -> ([a], g)
    

    现在使用它我们可以轻松地重新实现您的功能,如下所示:

    rndsel :: (Eq a, RandomGen g) => Int -> g -> [a] -> [a]
    rndsel n g = take n . fst . shuffle g