2017-09-30 39 views
2

我想寫會追加一個HList一個功能,我發現Updater是最接近我想要的東西:無形HList附加器

def appender[L <: HList, V, Out <: HList](hl: L, k: Witness, v: V)(implicit updater: Updater.Aux[L, FieldType[k.T, V], Out]) : Out = { 
    updater(hl, field[k.T](v)) 
    } 

我有這個功能的更新和追加一個HList,但我想禁用更新並只允許追加功能,以便:

val hl = 'field1 ->> 1 :: HNil 
appender(hl, 'field2, 2) //should compile 
appender(hl, 'field1, 2) //should fail 

目前都編譯。無論如何,我可以用無形表達這個約束嗎?我想也許有可能要求證據表明Out類型是一種比類型更長的元素?

回答

3

使用shapeless.ops.record.LacksKey

def appender[L <: HList, V, Out <: HList](hl: L, k: Witness, v: V)(implicit 
                    updater: Updater.Aux[L, FieldType[k.T, V], Out], 
                    lk: LacksKey[L, k.T]) : Out = { 
    updater(hl, field[k.T](v)) 
    } 
+1

@jamborta'L LacksKey K'檢查列表'L'是否不包含任何帶有鍵「K」的元素(檢查以確保''FieldType [K,_] L')。這限制了'Updater'只能追加到列表中,因爲如果密鑰已經存在,它只能修改列表 – HTNW

1

留給後人,這是一個使用你的長度檢查想法的答案。但是,LacksKey的方式更好。另外,如果您重新使用密鑰但使用不同類型(因爲畢竟該類型實際上是密鑰的一部分),那麼Updater會創建重複密鑰,這意味着此append也會相同。

def append[ 
    Value, 
    In <: HList, 
    Out <: HList, 
    InSize <: Nat, 
    OutSize <: Nat, 
    AddedNum <: Nat 
](in: In, key: Witness, value: Value)(implicit 
    update: Updater.Aux[In, FieldType[key.T, Value], Out], 
    inSize: Length.Aux[In, InSize], 
    outSize: Length.Aux[Out, OutSize], 
    addedNum: ops.nat.Diff.Aux[OutSize, InSize, AddedNum], // ops.{hlist, nat}.Diff conflict 
    sizeRestriction: AddedNum =:= _1 // Bonus: error messages are fairly readable: "Cannot prove that AddedNum = Succ[_0]" (followed by a horrifyingly long "not enough arguments" error). 
): Out = update(in, field[key.T](value)) 

注意,都在你的計算類型級別的值需要類型參數,因爲你不能有提及在同一參數列表中其他參數類型的參數。你需要非常小心,不要讓編譯器做更多的事情,而不是去處理每一步。

+0

謝謝。這是一個有趣的方法。 – jamborta