編輯:
它seems,目前官方包處理記錄操作是purescript-record
- 你可以找到Builder.purs沒有提供merge
和build
功能:
> import Data.Record.Builder (build, merge)
> name = {name: "Jim"}
> age = {age: 37}
> :t (build (merge age) name)
{ name :: String
, age :: Int
}
API注:
該API看起來過於複雜 - 尤其是當您將其與簡單的unionMerge name age
調用(unionMerge
在本答案的末尾引用)。 Builder
存在的原因(以及此API)是性能。我可以向你保證:
> build (merge name >>> merge age) {email: "[email protected]"}
只創建一條新記錄。但是這個:
> unionMerge name (unionMerge age {email: "[email protected]"})
在執行期間創建兩條記錄。
什麼是更有趣的是如何Builder
,build
和merge
實現 - Builder
是圍繞功能NEWTYPE包裝(其成分只是功能組成)和build
僅僅是一條記錄的複製版本功能應用:
newtype Builder a b = Builder (a -> b)
build (Builder b) r1 = b (copyRecord r1)
在merge
有unsafeMerge
進行:
merge r2 = Builder \r1 -> unsafeMerge r1 r2
所以w ^我們正在獲得什麼?因爲我們可以確定中間結果不能逃避函數作用域,所以所有的轉換都可以在適當的位置執行。換句話說,這intermediate
值:
> intermediate = unionMerge name {email: "[email protected]"}
> unionMerge age intermediate
不能被「提取」從這裏開始:
> build (merge name >>> merge age) {email: "[email protected]"}
類型系統註釋:
似乎Purescript類型的系統可以處理這個問題,現在感謝來自Prim
的Union
類型等級:
The Union type class is used to compute the union of two rows
of types (left-biased, including duplicates).
The third type argument represents the union of the first two.
具有這種 「魔法類」(來源:slide 23):
Union r1 r2 r3 | r1 r2 -> r3, r1 r3 -> r2
舊方法(仍然有效,但不是首選):
有purescript-records包暴露unionMerge
這不正是你想要(在新的psci我們不必使用let
):
> import Data.Record (unionMerge)
> name = {name: "Jim"}
> age = {age: 37}
> :t (unionMerge age name)
{ name :: String
, age :: Int
}
很酷,感謝您的解釋。但只是爲了澄清一些問題:它如何與Eff rowtype一起工作。據我所知,Eff行類型是一些如何由不同的效果類型「組成」。它在那裏如何工作? –
它依賴於統一的類型,所以在上面的例子中,如果我們用'{name :: String,age :: Int,address :: String}'調用'something',我們最終會得到'r〜(age: :Int,address :: String)'in'{name :: String | r}'。 「Eff」的工作方式類似,我們從來沒有真正有過兩種不同的「eff」值從不同的參數組合出來產生新的東西的東西。 –
好的,我覺得我不敢恭維。非常感謝。 –