Forcing a generic parameter

时间:2016-10-20 20:04:38

标签: f#

I have the following issue:
I have 2 types that are paremterized and that should work with a generic function if both types have the same type parameters

type A<'a> = A of 'a
type C<'a> = C of 'a

let inline save ((A a) :A<'a>) ((C c):C<'a>) = saveToDB (a :: c :: []) |> ignore

save (A 1) (C 2)
save (A "1") (C "2")

Now imagine a function that should execute the save but with different types which will be instantiated via some indicator

let inline save indicator (otherval:C<'a>) =
    match indicator with
    | "i" -> save (A 1) otherval
    | "s" -> save (A "s") otherval

In this case I get an error on | "s" -> adder (A "s") otherval saying that otherval should be of type C<int>

Any idea on how to approach this?

2 个答案:

答案 0 :(得分:3)

基于Julien Roncaglia的回答,这种方法至少应该是类型安全的,因为我们在守卫时使用:

let inline save ((A a) :A<'a>) ((C c):C<'a>) = saveToDB (a :: c :: []) |> ignore

let boxToGenericC<'a, 'b> (c: C<'a>) =
    unbox<C<'b>>(box(c))

let save1 indicator (otherval:C<'a>) =
    match indicator with
    | "i" when typeof<'a> = typeof<System.Int32> -> save (A 1) (boxToGenericC<'a, int> otherval)
    | "s" when typeof<'a> = typeof<string>-> save (A "s") (boxToGenericC<'a, string> otherval)

并尝试执行save1 "s" (C 1)会导致模式匹配失败。

答案 1 :(得分:2)

虽然它可能不是一个“干净”的设计(我没有看到一个没有改变你的规格),你可以告诉类型系统停止关怀:

  .hovereffect img{
    display: block;
    position: relative;
    max-width: none;
    width: calc(100% + 20px);
    -webkit-transition: opacity 0.35s, -webkit-transform 0.35s;
    transition: opacity 0.35s, transform 0.35s;
    -webkit-transform: translate3d(-10px,0,0);
    transform: translate3d(-10px,0,0);
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
  }
  .hovereffect:hover img{
    opacity: 0;
    filter: alpha(opacity=40);
    -webkit-transform: translate3d(0,0,0);
    transform: translate3d(0,0,0);
  }
  .hovereffect a, .hovereffect p{
    color: #FFF;
    opacity: 0;
    filter: alpha(opacity=0);
    -webkit-transition: opacity 0.35s, -webkit-transform 0.35s;
    transition: opacity 0.35s, transform 0.35s;
    -webkit-transform: translate3d(100%,0,0);
    transform: translate3d(100%,0,0);
  }
  .hovereffect:hover a, .hovereffect:hover p{
    opacity: 1;
    filter: alpha(opacity=100);
    -webkit-transform: translate3d(0,0,5);
    transform: translate3d(0,0,0);
    text-decoration: none;
    color: #fff;
  }

它有效,但你失去了一些检查:

let inline firstval indicator:A<'a> =
    let boxed =
        match indicator with
        | "i" -> box (A 1)
        | "s" -> box (A "s")

    unbox<A<'a>> boxed

let inline save2 indicator (otherval:C<'a>) =
    save (firstval indicator) otherval

save2 "i" (C 2)

save2 "s" (C "2")
  

无法将类型为'A`1 [System.String]'的对象转换为'A`1 [System.Int32]'。