如何在 Elm 中创建一组满足给定条件的三元组?
How does one create a set of 3-tuples in Elm meeting a given condition?
我知道 Elm 既没有 for 循环(不足为奇)也没有理解(有点令人惊讶)。我知道 map
用于人们可能期望理解的地方。
但是如何从三个范围变量构建一组三元组呢?我对生成这些元组很感兴趣,在 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)]
我不确定如何在 Elm 中生成它。这是我试过的:
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
代替吗?)并且对于大的数字范围我想按需生成值。有没有办法将值生成为信号?
扁平化
使您的示例按您想要的方式工作的最小更改是将外部两个 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)
我知道 Elm 既没有 for 循环(不足为奇)也没有理解(有点令人惊讶)。我知道 map
用于人们可能期望理解的地方。
但是如何从三个范围变量构建一组三元组呢?我对生成这些元组很感兴趣,在 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)]
我不确定如何在 Elm 中生成它。这是我试过的:
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
代替吗?)并且对于大的数字范围我想按需生成值。有没有办法将值生成为信号?
扁平化
使您的示例按您想要的方式工作的最小更改是将外部两个 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)