将列表映射到转移的自我

Map List onto shifted self

我终于找到了使用 elm 进行函数式编程的绝佳切入点,天哪,我喜欢它吗,但我仍然缺乏一些关于一些概念的基本优雅。

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

我想这可以归结为如下内容 (<->是向量减法运算符):

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

但我并没有真正令人满意的方法来完成 shiftr 的方法。

但 Whosebug 的规则要求它,这是我尝试过的。我写了一个 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) 让我挠头几次 :)

谢谢您,非常感谢您使用这种恰当的语言!

就在我 "hung up" 之后,我想到了这个,但我相信如果它是正确的(并且它只适用于 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)

如果 Elm 有内置的 init and last 函数,这可能会更干净。

您可以通过进行一些模式匹配来摆脱所有这些 Maybe。这是我仅使用模式匹配和累加器的尝试。

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 did 有一个 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