在没有 Maybe 的情况下在 Elm 中转置
Transpose in Elm without Maybe
我有一个整数列表列表[[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 -> []
但问题是编译器不喜欢 head 和 tail 操作,想要 return Maybe 类型。
如何在 elm 中正确转置列表?
这取决于...
考虑到所有的边缘情况,你想彻底地做到这一点吗?还是以快速而肮脏的方式进行?我所说的边缘案例是一个列表列表,其中的子列表具有不同的长度。
非常肮脏的方式
在极端情况下你会遇到程序崩溃
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)
_ ->
[]
祝那些随机程序崩溃好运,不要说我没有警告你!
不关心边界情况(或者:较短的行没问题)
在边缘情况下你会得到: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)
拥抱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
您有时可以使用 List.take 1
/List.drop 1
代替 List.head
/List.tail
,在这样的情况下,空 List
更有意义] 而不是 Nothing
.
在 transpose
的例子中,如果你想这样写它,当列表长度不相等时它会删除任何额外的值(即只转置 "as much as it can" 取决于最短的列表),您可以使用:
transpose : List (List a) -> List (List a)
transpose ll =
let heads = List.map (List.take 1) ll |> List.concat
tails = List.map (List.drop 1) ll
in
if | List.length heads == List.length ll ->
heads::(transpose tails)
| otherwise ->
[]
transpose [[1,2,3,4],[1,2,3,4]] --> [[1,1],[2,2],[3,3],[4,4]]
transpose [[10,11],[20],[],[30,31,32]] --> []
如果你想让它不断地从列表中取出直到它们全部消失(即根据最长的列表转置 "as much as it can"),你可以使用:
transpose : List (List a) -> List (List a)
transpose ll =
let heads = List.map (List.take 1) ll |> List.concat
tails = List.map (List.drop 1) ll
in
if | List.isEmpty heads ->
[]
| otherwise ->
heads::(transpose tails)
transpose [[1,2,3,4],[1,2,3,4]] --> [[1,1],[2,2],[3,3],[4,4]]
transpose [[10,11],[20],[],[30,31,32]] --> [[10,20,30],[11,31],[32]]
在矩阵格式正确的情况下,两者都同样有效,因此如果您想检查边缘情况并做其他事情,您可以先做。他们只是处理边缘情况有点不同。
我有一个整数列表列表[[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 -> []
但问题是编译器不喜欢 head 和 tail 操作,想要 return Maybe 类型。
如何在 elm 中正确转置列表?
这取决于...
考虑到所有的边缘情况,你想彻底地做到这一点吗?还是以快速而肮脏的方式进行?我所说的边缘案例是一个列表列表,其中的子列表具有不同的长度。
非常肮脏的方式
在极端情况下你会遇到程序崩溃
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)
_ ->
[]
祝那些随机程序崩溃好运,不要说我没有警告你!
不关心边界情况(或者:较短的行没问题)
在边缘情况下你会得到: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)
拥抱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
您有时可以使用 List.take 1
/List.drop 1
代替 List.head
/List.tail
,在这样的情况下,空 List
更有意义] 而不是 Nothing
.
在 transpose
的例子中,如果你想这样写它,当列表长度不相等时它会删除任何额外的值(即只转置 "as much as it can" 取决于最短的列表),您可以使用:
transpose : List (List a) -> List (List a)
transpose ll =
let heads = List.map (List.take 1) ll |> List.concat
tails = List.map (List.drop 1) ll
in
if | List.length heads == List.length ll ->
heads::(transpose tails)
| otherwise ->
[]
transpose [[1,2,3,4],[1,2,3,4]] --> [[1,1],[2,2],[3,3],[4,4]]
transpose [[10,11],[20],[],[30,31,32]] --> []
如果你想让它不断地从列表中取出直到它们全部消失(即根据最长的列表转置 "as much as it can"),你可以使用:
transpose : List (List a) -> List (List a)
transpose ll =
let heads = List.map (List.take 1) ll |> List.concat
tails = List.map (List.drop 1) ll
in
if | List.isEmpty heads ->
[]
| otherwise ->
heads::(transpose tails)
transpose [[1,2,3,4],[1,2,3,4]] --> [[1,1],[2,2],[3,3],[4,4]]
transpose [[10,11],[20],[],[30,31,32]] --> [[10,20,30],[11,31],[32]]
在矩阵格式正确的情况下,两者都同样有效,因此如果您想检查边缘情况并做其他事情,您可以先做。他们只是处理边缘情况有点不同。