如何在Elm中创建一组符合给定条件的3元组?

时间:2015-04-14 03:39:58

标签: signals elm

我知道Elm既没有for循环(也没有惊讶),也没有理解(略微令人惊讶)。我知道map用于人们可能期望理解的地方。

但是你如何从三个范围变量构建一组3元组?我对生成这些元组很感兴趣,这在Python中很容易产生:

>>> [(x,y,z) for z in range(5) for y in range(z) for x in range(y)]
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3), (0, 1, 4), (0, 2, 4), 
(1, 2, 4), (0, 3, 4), (1, 3, 4), (2, 3, 4)]

我不确定如何在榆树中制作这个。这就是我的尝试:

import Text (asText)
import List (map)
main =
  asText <| map (\z -> map (\y -> map (\x -> (x,y,z)) [0..y-1]) [0..z-1]) [0..4]

这会产生

[[],[[]],[[],[(0,1,2)]],[[],[(0,1,3)],[(0,2,3),(1,2,3)]],
[[],[(0,1,4)],[(0,2,4),(1,2,4)],[(0,3,4),(1,3,4),(2,3,4)]]]

虽然接近但需要展平。

我是Elm的新手,所以我不知道生成这些元组的正确方法。我可能弄清楚如何压扁我想出的列表,代码本身看起来相当冗长(我应该使用List.map3吗?)而对于大数量范围我想要按需生成值。有没有办法将值生成为信号,也许?

1 个答案:

答案 0 :(得分:3)

压扁

使您的示例按您希望的方式工作的最小更改是使用map更改外部两个concatMap

import Text (asText)
import List (map,concatMap)
main =
  asText <| concatMap (\z -> concatMap (\y -> map (\x -> (x,y,z)) [0..y-1]) [0..z-1]) [0..4]

根据您喜欢阅读代码的方式,您可能更喜欢这样:

import Text (asText)
import List (map,concatMap)

list = 
  [0..4] |> concatMap (\z -> 
    [0..z-1] |> concatMap (\y -> 
      [0..y-1] |> map (\x -> (x,y,z))))

main =
  asText list

这实际上不是您可以使用map3执行的操作,因为这仅适用于不相互依赖的列表。

按需生成

信号可能不便于按需生成。除非涉及明显的时间组件,即使如此,如果列表结束信号也不是正确的选择。

要生成内容,您应该定义一个惰性序列。如果要记住惰性动作,可以使用函数来模拟懒惰或使用Lazy library

要创建自己的懒惰序列,只需使用类似:

type LazySeq a = End | Item a (() -> LazySeq a)

map : (a -> b) -> LazySeq a -> LazySeq b
map f ls =
  case ls of
    End -> End
    Item i next -> Item (f i) (\() -> map f (next ()))

append : LazySeq a -> LazySeq a -> LazySeq a
append l r =
  case l of
    End -> r
    Item i next -> Item i (\() -> append (next ()) r)

concat : LazySeq (LazySeq a) -> LazySeq a
concat ls =
  case ls of
    End -> End
    Item i next ->
      case i of
        End -> concat (next ())
        Item i2 next2 -> Item i2 (\() -> append (next2 ()) (concat (next ())))

concatMap : (a -> LazySeq b) -> LazySeq a -> LazySeq b
concatMap f ls =
  concat (map f ls)