簡體   English   中英

為什么函數不能采用僅受類型類約束的類型?

[英]Why can't a function take a type constrained only by a typeclass?

我沒有足夠的詞匯來表達這個問題(因此,為了尋找答案,如果答案很容易獲得,那么道歉)。 考慮以下

class RunFoo m where
  runFoo :: m a -> a

class RunFooWrapper m where
  doRunFoo :: (RunFoo n) => n a -> m a

newtype RunFast a = RunFast a

newtype RunSlow a = RunSlow a

fooExample :: (RunFoo m) => m Bool
fooExample = undefined

fooWrapperExample :: (RunFooWrapper m) => m Bool
fooWrapperExample = doRunFoo fooExample

這不編譯: Could not deduce (RunFoo n0) arising from a use of 'doRunFoo'

似乎編譯器(GHC 7.10)堅持從fooExample具體實例化m ,因此拒絕繼續。 但在這種情況下,我無法fooExample為什么程序是錯誤類型的 - fooExample顯式定義了RunFoo m ,所有doRunFoo需要的是RunFoo x 那么為什么這不起作用呢?

作為一個補充問題,是否存在某種特殊的擴展(可能與存在類型有關),允許這樣的程序? 理想情況下,我希望能夠說doRunFoo采用存在的任何定義(?)作為RunFoo m => m (而不是采用任何具體的RunFoo實例)。

動機

我想創建可組合函數,這些函數在類型類約束的類型的某些方面運行 - 我可以提供一個具體的例子,說明我的意思,如果有必要的話!

編輯更多的動力和替代實施

我對一般情況下這個問題的答案感到好奇,但我想我會在上下文中添加一些我遇到的問題,我真正想要的是monad之間的一種約束委托。 所以我想在一個monad中編寫函數,只能通過在另一個類型類中調用monad的類型類來約束。 然后可以在不同的上下文中運行頂級函數,執行相同的邏輯,但根據包裝monad將底層實現換出。 由於包裝和實現monad之間存在一對一的對應關系,我可以使用類型系列來實現這一點,所以

class (RunFoo (RunFooM m)) => RunFooWrapper m where
  type RunFooM m :: * -> *
  doRunFoo :: RunFooM m a -> m a

instance RunFooWrapper RunFooWrapperSlow where 
  type RunFooM RunFooWrapperSlow = RunSlow
  doRunFoo :: [...]

這意味着fooExample m的分辨率由包裝器monad的類上下文決定,並且似乎工作正常,但與haoformayor提供的解決方案相比,它是一個非常狹窄的解決方案。

RankNTypes

{-# language RankNTypes #-}    

class RunFoo m where
  runFoo :: m a -> a

class RunFooWrapper m where
  doRunFoo :: (forall n. RunFoo n => n a) -> m a

fooExample :: RunFoo m => m Bool
fooExample = undefined

fooWrapperExample :: RunFooWrapper m => m Bool
fooWrapperExample = doRunFoo fooExample

(forall n. RunFoo n => na) -> ma是關鍵區別。 它允許您傳入fooExample ,其類型為forall m. RunFoo m => m Bool forall m. RunFoo m => m Bool (編譯器隱式添加了forall ),因此mn結合,每個人都很高興。 雖然我無法讀懂思想,但我相信這種類型反映了你的真實意圖。 您只需要一個RunFoo實例,僅此而已將n作用於第一個參數提供它。

問題是你的代碼被隱式輸入為forall n. RunFoo n => na -> ma forall n. RunFoo n => na -> ma 這意味着你需要首先選擇一個n ,使得RunFoo n然后提出一個類型為na的值作為第一個參數傳入。 移動括號的這種簡單行為(增加n的等級)完全改變了含義。

有關具有相同問題的人的示例,請參閱此Stack Overflow問題 有關RankNTypes的更好解釋,請參閱Oliver的博客文章

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM