2017-01-31 37 views
0

我想傳遞一個函數:從應用程序A功能與類型不透明的庫,但特定於應用程序

f :: a -> CmdRequest -> (a, CmdResponse) 

到系統S.

小號

  • 定義CmdRequest和CmdResponse
  • 初始化時:給定/商店f
  • 在初始化:存儲的a初始值(如一個不透明的值,S不能看到任何a結構)
  • 呼叫f(如系統操作的一部分)
  • 傳遞它預先存儲a值(從先前的呼叫或系統初始化)返回類型的
  • 存儲所得到的第一a部件

  • 定義f
  • 在初始化:在初始化時通過f至S
  • :傳遞至S
  • a初始值可以使用特定類型a(例如,Data.HashMap)
  • f被稱爲它可以看到內部結構(如Data.HashMap)a

這怎麼可以在Haskell/GHC中完成?

S的狀態是什麼類型的簽名? 我認爲它可以作爲

State a :: ... 

一樣簡單,但有沒有辦法隱藏a? (其中「隱藏」意味着不指定類型參數State

我最初嘗試過類型和存在類型,但卡住了。

example on github

A        S     S's State 
    initialization 
.        .      . 
.        .      . 
.        .      . 
|        |      | 
x---------- pass f ----------->|      | 
|        x----- store f -------->| 
x--------------- a ----------->|      | 
|        x----- store a -------->| 
           |      | 
           .      . 
           .      . 
           .      . 
    system operation 
           |      | 
           |      | 
           x------- get f -------->| 
           |      | 
           x------- get a -------->| 
           |      | 
|<---- call f a CmdRequest ----|      | 
|        |      | 
|-- return (a', CmdResponse) ->|      | 
|        |      | 
|        x----- store a' ------->| 
|        |      | 
.        .      . 
.        .      . 
.        .      . 
|<--- call f a' CmdRequest ----|      | 
|        |      | 
|- return (a'', CmdResponse) ->|      | 
|        |      | 
|        x----- store a'' ------>| 
|        |      | 
.        .      . 
.        .      . 
.        .      . 
+2

爲什麼特別需要做什麼?使用L的API包含函數如'fooWithCallback ::(a - > CmdRequest - >(a,CmdResponse)) - > { - foo actions的類型 - }'有什麼問題? foo動作的類型必須有一個'a'的參數,但它確實不需要任何技巧或努力工作。 –

+1

有關此類API的示例,請查看['atomicModifyIORef'](https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-IORef.html#v:atomicModifyIORef)。它具有類型'IORef a - >(a - >(a,b)) - > IO b',它基本上與'(a - >() - >(a,b)) - > IORef a - > IO b';眯起眼睛,你可以看到'()'是一種(尤其是無聊的)'CmdRequest','b'作爲一種'CmdResponse',和'IORef a - > IO b'作爲foo動作的類型這符合我在之前的評論中提出的形狀。 –

+0

我可以看到沒有問題。請記住,如果A定義了'f'而'CmdRequest'是不透明的,那麼'f'只能使用由L導出的函數來處理它的'CmdRequest'參數。 – chi

回答

0

具有如下功能不透明的庫,但具體到一個應用程序是Haskell的麪包和奶油。例如,請考慮來自「容器」包的Data.Map

地圖m :: Map k a是將密鑰k與值a相關聯的一段數據。數據。實際上,映射庫並不需要知道其值的結構,實際上,在ka中保持Map多態性的定義排除了庫做什麼到鍵和值的內容。好吧,幾乎任何東西。類型化會話會稍微改變會話,並且如果用戶提供鍵或值的功能,則可以更改它們。但重要的一點仍然是,多態參數限制了庫中可以做什麼。

您可以使用ExistentialTypes嘗試擺脫那個多態參數。在您的GitHub代碼方面,你可以使用類似定義狀態:

{-# Language ExistentialQuantification #-} 
import   Control.Concurrent.MVar 

data State = forall a . State 
    { 
    _nextValue  :: MVar a 
    , _applyLogEntry :: a -> CmdRequest -> (a, CmdResponse) 
    } 

在哪裏我已刪除了單子參數從data State m a爲清楚起見。值參數a現在被存在性量化隱藏。一直檢索存儲的值成爲一個棘手的問題。下面的代碼,

getStVal :: State -> IO a 
getStVal [email protected](State mva f) = takeMVar mva 

拋出一個編譯錯誤,提函數的預期類型是如何IO a(由於getStVal簽名),但實際類型IO a1(由於State型)。這是因爲getStVal需要特定的(雖然在編譯時未知)類型,而數據定義說該值可以是任何類型(但我們不能在編譯時假定任何特定類型)。

傳遞存儲值a到應用程序也沒有幫助,因爲根據a的值,應用程序無法改變其行爲。狀態值可以更新,但從不直接檢查。 (您可以包含類型類別信息,以表示某些方法(例如show)可以應用於該類型。more info

還有其他擴展名您可以嘗試。最終,我不確定GADT或RankNType會更好。你必須說服編譯器 - 不知何故 - 你的程序將能夠使用未知類型。但實際上,多態參數通常是實現這一目的的最佳方式。

+0

你說得對,我所說的L實際上不是一個圖書館。但它也不是客戶端/服務器。現在我只是改變了(以上)我稱之爲L/Libary的S/System。所以S是一個獨立的運行系統,它有回調。你也是對的,這是簡單的參數多態 - 只是給S添加一個類型參數來解決「問題」。我已經添加了一個這樣的參數解決方案的鏈接。我真正的問題(無可否認,我的表述並不太好)是否有辦法在沒有類型參數的情況下執行此操作(請參閱我編輯/更新的問題)。 – haroldcarr

+0

FWIW:我確實使用haskell綁定到ZeroMQ – haroldcarr

+0

@haroldcarr,我根據更新後的問題更新了答案。我希望它有幫助。這是一個廣泛的問題,所以我不知道如何解決它。我已經玩了一些語言擴展。通常這很有趣,但我很少選擇使用它們。 –

相關問題