F# 在异构列表上,是否可以使压缩和解压与原始列表相同?

F# 在异构列表上,是否可以使压缩和解压与原始列表相同?,f#,F#,我正在讨论异构列表上下文中的zip操作。我正在开发一种轻度依赖类型的语言,将它们用作元组 type T = | S of string | R of T list let rec zip l = let is_all_r_empty x = List.forall (function R [] -> true | _ -> false) x let rec loop acc_total acc_head acc_tail x = match x wi

我正在讨论异构列表上下文中的zip操作。我正在开发一种轻度依赖类型的语言,将它们用作元组

type T =
| S of string
| R of T list

let rec zip l =
    let is_all_r_empty x = List.forall (function R [] -> true | _ -> false) x
    let rec loop acc_total acc_head acc_tail x =
        match x with
        | S _ :: _ -> R l
        | R [] :: ys -> 
            if List.isEmpty acc_head && is_all_r_empty ys then List.rev acc_total |> R 
            else R l
        | R (x :: xs) :: ys -> loop acc_total (x :: acc_head) (R xs :: acc_tail) ys
        | [] -> 
            match acc_tail with
            | _ :: _ -> loop ((List.rev acc_head |> zip) :: acc_total) [] [] (List.rev acc_tail)
            | _ -> List.rev acc_total |> R
    loop [] [] [] l

let rec unzip l =
    let transpose l =
        let is_all_empty x = List.forall (function _ :: _ -> false | _ -> true) x
        let rec loop acc_total acc_head acc_tail = function
            | (x :: xs) :: ys -> loop acc_total (x :: acc_head) (xs :: acc_tail) ys
            | [] :: ys -> 
                if List.isEmpty acc_head && is_all_empty ys then loop acc_total acc_head acc_tail ys 
                else l
            | [] ->
                match acc_tail with
                | _ :: _ -> loop (List.rev acc_head :: acc_total) [] [] (List.rev acc_tail)
                | _ -> List.rev acc_total
        loop [] [] [] l
    let is_all_r x = List.forall (function R _ -> true | _ -> false) x
    match l with
    | R x when is_all_r x -> List.map unzip x |> transpose |> List.map R
    | R x -> x
    | S _ -> failwith "Unzip called on S."

//let a = R [R [S "a"; S "t"]; R [S "b"; S "w"]; R [S "c"; S "e"]]
//let b = R [R [S "1"; S "4"]; R [S "5"; S "r"]; R [S "3"; S "6"]]
//let c = R [R [S "z"; S "v"]; R [S "x"; S "b"]; R [S "c"; S "2"]]
//
//let t3 = zip [a;b]
//let t4 = zip [t3;c]
//let u1 = unzip t4
//let r1 = u1 = [t3;c]
//let u2 = unzip t3
//let r2 = u2 = [a;b] // The above works fine on tuples with regular dimensions.

let a = R [R [S "q"; S "w"; S "e"]]
let b = R [R [S "a"; S "s"]; R [S "z"]; S "wqe"]
let ab = [a;b]
let t = zip ab
let t' = unzip t
ab = t' // This is false, but I would like the ziping and then unziping to be reversible if possible.
压缩和解压通常可以表示为一个维度移位或一系列转置。这就是这两个功能所做的一切

它们在规则元组上表现良好,但我希望zip+unzip在不规则元组上也是同构的。我的直觉告诉我,这对他们要求太多了

我需要第二个意见。

#r./../packages/FsCheck.2.8.0/lib/net452/FsCheck.dll”
#r "../../packages/FsCheck.2.8.0/lib/net452/FsCheck.dll"

type T =
| S of string
| VV of T list

let transpose l on_fail on_succ =
    let is_all_vv_empty x = List.forall (function VV [] -> true | _ -> false) x
    let rec loop acc_total acc_head acc_tail = function
        | VV [] :: ys -> 
            if List.isEmpty acc_head && is_all_vv_empty ys then 
                if List.isEmpty acc_total then failwith "Empty inputs in the inner dimension to transpose are invalid."
                else List.rev acc_total |> on_succ
            else on_fail ()
        | VV (x :: xs) :: ys -> loop acc_total (x :: acc_head) (VV xs :: acc_tail) ys
        | _ :: _ -> on_fail ()
        | [] -> 
            match acc_tail with
            | _ :: _ -> loop (VV (List.rev acc_head) :: acc_total) [] [] (List.rev acc_tail)
            | _ -> List.rev acc_total |> on_succ
    loop [] [] [] l

let rec zip l = 
    match l with
    | _ :: _ -> transpose l (fun _ -> l) (List.map (function VV x -> zip x | x -> x)) |> VV
    | _ -> failwith "Empty input to zip is invalid."

let rec unzip l = 
    let is_all_vv x = List.forall (function VV _ -> true | _ -> false) x
    match l with
    | VV x ->
        match x with
        | _ :: _ when is_all_vv x -> let t = List.map (unzip >> VV) x in transpose t (fun _ -> x) id
        | _ :: _ -> x
        | _ -> failwith "Empty inputs to unzip are invalid."
    | S _ -> failwith "Unzip called on S."

open FsCheck
open System

let gen_t =
    let mutable gen_t = None
    let gen_s () = Gen.map S Arb.generate<string>
    let gen_vv size = Gen.nonEmptyListOf (gen_t.Value size) |> Gen.map VV
    gen_t <- 
        fun size -> 
            match size with
            | 0 -> gen_s()
            | _ when size > 0 -> Gen.oneof [gen_s (); gen_vv (size-1)] 
            | _ -> failwith "impossible" 
        |> Some
    gen_t.Value
    |> Gen.sized

let gen_t_list_irregular = Gen.nonEmptyListOf gen_t
let gen_t_list_regular = Gen.map2 List.replicate (Gen.choose(1,10)) gen_t

type MyGenerators =
    static member Tuple() = Arb.fromGen gen_t
    static member TupleList() = Arb.fromGen gen_t_list_regular
Arb.register<MyGenerators>()

let zip_and_unzip orig = zip orig |> unzip
let zip_and_unzip_eq_orig orig = zip_and_unzip orig = orig

// For regular tuples it passes with flying colors.

Check.One ({Config.Quick with EndSize = 10}, zip_and_unzip_eq_orig)

// I can't get it to be isomorphic for irregularly sized arrays as expected.

//let f x = 
//    let x' = zip x
//    printfn "x'=%A" x'
//    printfn "unzip x'=%A" (unzip x')
//    printfn "zip_and_unzip_eq_orig x=%A" (zip_and_unzip_eq_orig x)
//
//f [VV [VV [S "12"; S "qwe"]; VV [S "d"]]; VV [VV [S ""; S "ug"]; VV [S ""]]]
T型= |弦乐 |T表的VV 让l在成功时转置失败= 设为_all_vv_empty x=List.forall(函数vv[]->true | u->false)x 让rec循环acc\总acc\头部acc\尾部=功能 |VV[]::ys-> 如果List.isEmpty acc\u head&&is\u all\u vv\u为空,则 如果List.isEmpty acc_total,则failwith“要转置的内部维度中的空输入无效。” else List.rev acc|U total|>on|U SUCCC 否则将失败() |VV(x::xs)::ys->循环acc_总计(x::acc_头)(VV xs::acc_尾)ys |_u::u->on_fail() | [] -> 将acc_尾与 |循环(VV(List.rev acc\u head)::acc\u总计)[[](List.rev acc\u tail) |->List.rev acc|u total|>成功 循环[][]l 让rec zip l= 匹配 ||::|->转置l(fun |->l)(List.map(函数vvx->zip x | x->x))|>VV |->failwith“zip的空输入无效。” 让rec解压l= 设为_all_vv x=List.forall(函数vv->真|->假)x 匹配 |VV x-> 将x与 |什么时候是转置t(fun->x)id中的所有vv x->let t=List.map(解压>>vv)x |_u::ux->x |->failwith“要解压缩的空输入无效。” |S->failwith“在S上解压调用” 开放式FsCheck 开放系统 让gen_t= 设可变gen\u t=None 让gen_s()=gen.map s Arb.generate 让gen_vv size=gen.nonEmptyListOf(gen_t.Value size)|>gen.map vv 一般 大小与 |0->gen_s() |当尺寸>0->Gen.oneof[Gen_s();Gen_vv(尺寸-1)] |用“不可能”表示失败 |>一些 发电价值 |>一般大小 让gen\u t\u list\u unregular=gen.nonEmptyListOf gen\u t 让gen\u t\u list\u regular=gen.map2 list.replicate(gen.choose(1,10))gen\t 类型MyGenerator= 静态成员元组()=Arb.fromGen\u t 静态成员TupleList()=Arb.fromGen\u t\u列表\u常规 仲裁寄存器() 让zip_和解压orig=zip orig |>解压 让zip_和解压_eq_orig orig=zip_和解压orig=orig //对于常规元组,它会以优异的成绩通过。 Check.One({Config.Quick with EndSize=10},zip_和_unzip_eq_orig) //对于大小不规则的数组,我不能像预期的那样使其同构。 //设fx= //设x'=zip x //printfn“x'=%A“x” //printfn“解压x'=%A”(解压x') //打印fn“zip_和解压_eq_orig x=%A”(zip_和解压_eq_orig x) // //f[VV[VV[S”12;S“qwe”];VV[S“d”];VV[VV[S”“;S“ug”];VV[S”“]]
不管怎样,我试着,我不知道如何使这对不规则大小的元组同构,我觉得不太可能有人会以不同的方式告诉我,所以我现在把上面的尝试作为一个答案

从好的方面来看,基于上面的测试,我非常确信它对于所有规则大小的元组都应该是同构的。我想这就足够了。与问题中的示例相比,我将代码收紧了一点

这个不规则的压缩和解压问题将成为一个有趣的数学难题