将列表映射到移位的自我

时间:2016-04-07 19:47:52

标签: functional-programming elm

我终于找到了榆树功能编程的优秀切入点,男孩,我喜欢它,但我仍然缺乏一些关于一些概念的基本优雅。

我经常发现自己编写的代码类似于下面的代码,它似乎正在做它应该做的事情,但如果有经验的人可以提出更紧凑和直接的方法,我相信这可以提供一些有价值的见解,所以(u)的rcery。

我认为这可以归结为,如下所示 (<->是向量减法运算符):

edgeDirections : List Vector -> List Vector
edgeDirections corners = List.map2 (\p v -> p <-> v) corners (shiftr 1 corners)

但我对一个能做shiftr的方法的方法并不满意。

但是stackoverflow的规则要求它,这是我尝试过的。我写了一个关于shiftr的可能用法的丑陋示例(我绝对不喜欢Debug.crash而我对Maybe感到不满):

给定矢量列表(多边形的角点),通过计算每个角矢量与其前一个矢量的差值来计算方向矢量,从列表中第一个和最后一个条目之间的差异开始。

[v1,v2,v3] -> [v1-v3,v2-v1,v3-v2]

这里是:

edgeDir : Vector -> ( Maybe Vector, List Vector ) -> ( Maybe Vector, List Vector )
edgeDir p ( v, list ) =
  case v of
    Nothing ->
      Debug.crash ("nono")

    Just vector ->
      ( Just p, list ++ [ p <-> vector ] )


edgeDirections : List Vector -> List Vector
edgeDirections corners =
  let
    last =
      List.head <| List.reverse corners
  in
    snd <| List.foldl edgeDir ( last, [] ) corners


main =
  show <| edgeDirections [ Vector -1 0, Vector 0 1, Vector 1 0 ]

我很欣赏有关如何以更直接的方式实现此结果的任何见解,可能使用我尚未了解的现有语言结构,或者有关如何使用Maybe减轻痛苦的任何指示。后者可能Just是不可能的,但我确信前者将a)打击我并且b)让我刮挠我的头几次:))

谢谢你,非常感谢这种恰到好处的语言!

2 个答案:

答案 0 :(得分:2)

如果Elm具有内置init and last功能,这可能更清晰。

你可以通过做一些模式匹配来远离所有Maybes。这是我尝试使用模式匹配和累加器。

import List exposing (map2, append, reverse)

shiftr list = 
  let shiftr' acc rest =
    case rest of
      [] -> []
      [x] -> x :: reverse acc
      (x::xs) -> shiftr' (x::acc) xs
  in shiftr' [] list

edgeDirections vectors =
  map2 (<->) vectors <| shiftr vectors

另请注意(<->)的映射函数的缩写,相当于(\p v -> p <-> v)

假设Elm 具有initlast功能 - 让我们在这里快速定义:

init list =
  case list of
    [] -> Nothing
    [_] -> Just []
    (x::xs) -> Maybe.map ((::) x) <| init xs

last list =
  case list of
    [] -> Nothing
    [x] -> Just x
    (_::xs) -> last xs

然后您的shiftr功能可缩短为:

shiftr list =
  case (init list, last list) of
    (Just i, Just l) -> l :: i
    _ -> list

答案 1 :(得分:0)

在我“挂断”之后,我想出了这个,但我确信这仍然可以大大改进,如果它甚至是正确的(它只适用于n = 1)

shiftr : List a -> List a
shiftr list =
  let
    rev =
      List.reverse list
  in
    case List.head rev of
      Nothing ->
        list

      Just t ->
        [ t ] ++ (List.reverse <| List.drop 1 rev)


main =
  show (shiftr [ 1, 2, 3, 4 ] |> shiftr)