在没有Maybe的情况下在Elm中移植

les*_*how 3 transpose functional-programming list elm

我有一份整体清单清单 [[1,2,3,4],[1,2,3,4]]

我想转发它 [[1,1],[2,2],[3,3]...]

我有:

transpose : List (List a) -> List (List a)
transpose ll = case ll of
    ((x::xs)::xss) -> (x :: (List.map List.head xss)) :: transpose (xs :: (List.map List.tail xss))
    otherwise -> []
Run Code Online (Sandbox Code Playgroud)

但问题是编译器不喜欢head和tail操作,并希望返回Maybe类型.

如何在榆树中正确转置列表?

Apa*_*hka 5

这取决于......
考虑到所有的边缘箱,你想彻底做到这一点吗?或者快速而肮脏的方式呢?我所谓的边缘案例是列表的列表,其中子列表具有不同的长度.

很脏的方式

在边缘情况下,您会遇到程序崩溃

unsafeHead l =
  case l of
    (h :: t) -> h
    _ -> Debug.crash "unsafeHead called with empty list"

unsafeTail l =
  case l of
    (h :: t) -> t
    _ -> Debug.crash "unsafeTail called with empty list"

transpose ll =
  case ll of
    ((x::xs)::xss) ->
      let
        heads = 
          List.map unsafeHead xss

        tails =
          List.map unsafeTail xss
      in
        (x :: heads) :: transpose (xs :: tails)

    _ ->
      []
Run Code Online (Sandbox Code Playgroud)

祝那些随机程序崩溃好运,不要说我没有警告你!

不关心边缘情况(或者:较短的行是可以的)

在边缘情况下,您会得到: transpose [[10,11],[20],[],[30,31,32]] == [[10,20,30],[11,31],[32]]

transpose ll =
  case ll of
    [] ->
      []

    ([] :: xss) ->
      transpose xss

    ((x::xs) :: xss) ->
      let
        heads =
          List.filterMap List.head xss

        tails =
          List.filterMap List.tail xss
      in
        (x :: heads) :: transpose (xs :: tails)
Run Code Online (Sandbox Code Playgroud)

拥抱 Maybe

在边缘情况下,你得到一个 Nothing

如果你希望当你有所有子列表的大小相同列表的列表来转,你可以提上Maybe您从映射获得与S List.head/ List.tail:

transpose : List (List a) -> Maybe (List (List a))
transpose ll =
  case ll of
    ((x::xs)::xss) ->
      let
        heads =
          xss
          |> List.map List.head
          |> insideout

        tails =
          xss
          |> List.map List.tail
          |> insideout
      in
        (x #^ heads) ^#^ ((xs #^ tails) `Maybe.andThen` transpose)

    _ ->
      if ll == List.filter List.isEmpty ll then
        Just []
      else
        Nothing

----- Some helper functions: -----


mCons : a -> Maybe (List a) -> Maybe (List a)
mCons v ml = Maybe.map ((::) v) ml

v #^ ml = mCons v ml

-- this is really a Maybe.map2 (::) mv ml
-- but the standard library doesn't provide map2 :(
m2Cons : Maybe a -> Maybe (List a) -> Maybe (List a)
m2Cons mv ml =
  case (mv,ml) of
    (Just v, Just l) -> Just (v :: l)
    _ -> Nothing

mv ^#^ ml = m2Cons mv ml

-- list of justs to just of list
insideout : List (Maybe a) -> Maybe (List a)
insideout l =
  case l of
    [] -> Just []
    ((Just v) :: tail) -> v #^ insideout tail
    (Nothing :: _) -> Nothing
Run Code Online (Sandbox Code Playgroud)