什么是更好的方法来写[(-1,-1),( - 1,0),( - 1,1),(0,-1),(0,1),(1,-1), Haskell中的(1,0),(1,1)]?

Jak*_*son 16 haskell list-comprehension applicative

我遇到了一些我需要列表的情况:

[(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)] -- no (0,0)
Run Code Online (Sandbox Code Playgroud)

请注意,列表中没有(0,0).我使用(dx,dy)元组从坐标向上,向下,向左,向右和对角搜索.

每次我写它时,我觉得应该有一个更简洁,和/或更容易阅读的方式来定义它.我对Haskell比较陌生,而且我认为在Applicative/Functor/Monad技巧的某个地方应该有一个巧妙的方法来做到这一点.

我试过了:

[(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]
Run Code Online (Sandbox Code Playgroud)

有时最好把它写出来,但我认为这不是其中之一.一目了然(0,0)不包括在内并且你必须阅读它以注意模式.

map (\[a,b] -> (a,b)) $ delete [0,0] $ sequence $ replicate 2 [-1,0,1]
Run Code Online (Sandbox Code Playgroud)

我喜欢上面的那个,因为我把"2"放在那里,这是一个很好的明确方式来说"我们两次做同样的事情",但我不能接受前面的地图与大不安全的lambda和2个名字.

[(dx,dy) | let a = [-1,0,1], dx <- a, dy <- a, (dx,dy) /= (0, 0)]
Run Code Online (Sandbox Code Playgroud)

这个名称中包含太多名称,但完全按照设计使用列表推导.对于那些真正喜欢列表推导的人来说,可能更容易阅读,但我不喜欢所有的名字.

let x = [-1,0,1] in delete (0,0) $ (,) <$> x <*> x
Run Code Online (Sandbox Code Playgroud)

那个看起来更漂亮的imo,但我没有那个"2",我有一个名字.到目前为止,这是我的最爱,但它并不完美.

我想如果我理解如何更好地写这个,我可能会更深入地了解Functors/Monads等.我已经读了很多关于它们的内容,我听过很多像fmap/mconcat/etc这样的词,但我不知道在这种情况下要抓哪一个.

lef*_*out 25

实际上,我认为在这种情况下明确写出来确实是最好的.只需合理对齐,任何问题都无法保持开放:

neighbours = [ (-1,-1), (-1,0), (-1,1)
             , ( 0,-1),         ( 0,1)
             , ( 1,-1), ( 1,0), ( 1,1) ]
Run Code Online (Sandbox Code Playgroud)

没有任何其他选择可能比这更容易解释.

当然,还有更简洁的替代方案.作为一个物理学家,我倾向于

   [ (round $ - sin ?, round $ - cos ?) | ? <- [pi/4, pi/2 .. 2*pi] ]
Run Code Online (Sandbox Code Playgroud)

这当然是更昂贵的计算,但如果您只在一个地方定义此列表并从您的整个程序重新使用它并不重要.这里的订单不同,不确定是否重要.

  • BTW,角度解决方案是一个很好的例子,为什么Haskell实际上正确地使用[有关浮点数的枚举范围的有争议的定义](http://stackoverflow.com/questions/7290438/haskell-ranges-and-floats/7296160# 7296160):如果要求所有元素都是"<="终止,那么我们就不能确定接近"2π"的东西实际上会出现,因为它的浮点表示可能小于累积序列.因此`(0,-1)`可能会在结果中丢失. (6认同)

Ben*_*Ben 24

为什么不使用列表理解?他们可以有布尔警卫,所以排除(0,0)非常简单:

[(i,j) | i <- [-1..1], j <- [-1..1], (i,j) /= (0,0)]
Run Code Online (Sandbox Code Playgroud)

请注意,作为一个Haskell newb自己,可能有一种更紧凑/有效的方式来编写该保护表达式.尽管如此,这还是完成了工作.

  • 名称在列表理解的外部不可见. (6认同)

Dan*_*ner 15

Prelude Data.Ix Data.List> delete (0,0) (range ((-1,-1),(1,1)))
[(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]
Run Code Online (Sandbox Code Playgroud)


Tik*_*vis 6

这是一个使用以下内容的简洁版本Control.Applicative:

delete (0, 0) $ (,) <$> [-1..1] <*> [-1..1]
Run Code Online (Sandbox Code Playgroud)

就个人而言,我认为这看起来好多了&,只是$翻了个底.

(,) <$> [-1..1] <*> [-1..1] & delete (0, 0)
Run Code Online (Sandbox Code Playgroud)

您也可以使用liftA2而不是<$><*>:

liftA2 (,) [-1..1] [-1..1] & delete (0, 0)
Run Code Online (Sandbox Code Playgroud)

它在镜头库中定义,但您可以自己定义:

infixl 1 &
x & f = f x
Run Code Online (Sandbox Code Playgroud)

总而言之,我仍然更喜欢具有列表理解的版本,甚至只是具有良好缩进的文字列表.