2016-03-14 74 views
5

鑑於我在purescript如下因素記錄:結合記錄Purescript

let name = {name: "Jim"} 
let age = {age: 37} 

是有可能的兩個記錄在一個通用的方式結合一些如何? 喜歡的東西:

name 'comb' age 

這樣,我得到以下記錄:

{name: "Jim", age: 37} 

不知怎的,它似乎是可能的則Eff行類型,不過我很好奇,如果有可能與「正常' 記錄。我是purescript的新手,它的記錄語法。

非常感謝。

回答

5

目前無法做到這一點,因爲我們沒有辦法說一排沒有標籤或其他標籤。它可以有一個開放的記錄類型:

something :: forall r. { name :: String | r } -> ... 

但這隻能讓我們接受name一個記錄和任何其他標籤,它並沒有幫助我們,如果我們想結合,擴展或減從現在的記錄來看。

相結合的任意記錄的問題是,我們就會有一個類型的簽名是這樣的:

comb :: forall r1 r2. { | r1 } -> { | r2 } -> ??? 

我們需要一些方式來表達結果(???)是r1r2工會,也是我們'd也許想說r1的標籤不會與r2重疊。

在未來,這可能通過row constraints

+0

很酷,感謝您的解釋。但只是爲了澄清一些問題:它如何與Eff rowtype一起工作。據我所知,Eff行類型是一些如何由不同的效果類型「組成」。它在那裏如何工作? –

+0

它依賴於統一的類型,所以在上面的例子中,如果我們用'{name :: String,age :: Int,address :: String}'調用'something',我們最終會得到'r〜(age: :Int,address :: String)'in'{name :: String | r}'。 「Eff」的工作方式類似,我們從來沒有真正有過兩種不同的「eff」值從不同的參數組合出來產生新的東西的東西。 –

+0

好的,我覺得我不敢恭維。非常感謝。 –

7

編輯:

seems,目前官方包處理記錄操作是purescript-record - 你可以找到Builder.purs沒有提供mergebuild功能:

> 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]"}) 

在執行期間創建兩條記錄。

什麼是更有趣的是如何Builderbuildmerge實現 - Builder是圍繞功能NEWTYPE包裝(其成分只是功能組成)和build僅僅是一條記錄的複製版本功能應用:

newtype Builder a b = Builder (a -> b) 

build (Builder b) r1 = b (copyRecord r1) 

mergeunsafeMerge進行:

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類型的系統可以處理這個問題,現在感謝來自PrimUnion類型等級:

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 
}