2010-11-23 161 views
51

我在程序中使用了很多不同的記錄,其中一些使用了相同的字段名稱,例如,避免Haskell命名空間污染

data Customer = Customer { ..., foo :: Int, ... } 
data Product = Product { ..., foo :: Int, ... } 

現在的訪問「foo」函數被定義了兩次,我得到了「多次聲明」的錯誤。避免這種情況的一種方法是使用導入完全限定的不同模塊,或者只是重命名字段(我不想這麼做)。

在Haskell中正式提出處理這個問題的方法是什麼?

+3

我分擔你的痛苦。我來自OO世界。 – gawi 2010-11-24 01:47:35

+2

所以它看起來像我會去與合格的進口 - 至少對於這個項目。謝謝大家的答案!這是那些當我使用類型類時錯過方案宏擺脫幹違規的時刻之一...... – lbruder 2010-11-24 08:51:45

+1

我發現[此項目頁](https://ghc.haskell.org/trac/ghc/wiki/ Records/OverloadedRecordFields)關於GHC的OverloadedRecordFields擴展,以允許多個記錄數據類型共享相同的字段名稱。 – Alexey 2014-04-16 15:53:33

回答

22

這是一個非常毛茸茸的問題。有修復的記錄系統有幾個建議。有關說明,請參閱TDNRrelated discussion on cafe

使用當前可用的語言功能,我認爲最好的選擇是在兩個不同的模塊中定義這兩種類型,並進行合格的導入。最重要的是,如果你願意,你可以實現一些類型的機器。

在Customer.hs

module Customer where 
data Customer = Customer { ..., foo :: Int, ... } 

在Product.hs

module Product where 
data Product = Product { ..., foo :: Int, ... } 

在使用它們,Third.hs

module Third where 

import qualified Customer as C 
import qualified Product as P 

.. C.foo .. 
.. P.foo .. 

然而,我想這不會是在您遇到有關recursively dependent modules的問題之前已經太晚了。

12

(FYI,這個問題幾乎可以肯定是一式兩份)

解決方案:

1)前綴用標籤字段指示類型(非常常見)

data Customer = Customer {..., cFoo :: Int, ...} 

2)使用類型類(不太常見,像cFoo這樣的人抱怨前綴不方便,但顯然不是很糟糕,他們會寫一個類和實例或使用TH來做同樣的事情)。

class getFoo a where 
    foo :: a -> Int 

instance getFoo Customer where 
    foo = cFoo 

3)使用更好的字段名 如果字段實際上是不同的(這並不總是正確的,我的電腦有一個年齡一樣我的員工),那麼這是最好的解決辦法。

+0

我使用的更常見的標記語法是c_foo。 – sclv 2010-11-24 07:31:21

7

也見有包:http://chrisdone.com/posts/duck-typing-in-haskell

如果你真的需要擴展現在的記錄,你可以隨時使用HList。但我不會推薦這個,直到你對中型高級Haskell非常熟悉和舒適,即使這樣我也會三重檢查你是否需要它。

Haskelldb有一個稍微更輕量級版本:http://hackage.haskell.org/packages/archive/haskelldb/2.1.0/doc/html/Database-HaskellDB-HDBRec.html

然後還有的可擴展的紀錄,另一個版本的柚子FRP庫的一部分:http://hackage.haskell.org/package/grapefruit-records

同樣,你的目的,我硬着頭皮只需重命名這些字段。但是這些參考文獻是要表明,當你真的需要可擴展記錄的全部功能時,有辦法做到這一點,即使沒有一個像精心設計的語言擴展那樣愉快。

2

有一個語言擴展DuplicateRecordFields允許的領域職能重疊,使公司類型由類型註釋來推斷。

這裏是一個小例子(haskell-stack腳本):

#!/usr/bin/env stack 
-- stack runghc --resolver lts-8.20 --install-ghc 

{-# LANGUAGE DuplicateRecordFields #-} 

newtype Foo = Foo { baz :: String } 
newtype Bar = Bar { baz :: String } 

foo = Foo { baz = "foo text" } 
bar = Bar { baz = "bar text" } 

main = do 
    putStrLn $ "Foo: " ++ baz (foo :: Foo) -- Foo: foo text 
    putStrLn $ "Bar: " ++ baz (bar :: Bar) -- Bar: bar text 
相關問題