2013-01-04 189 views
5

我正在研究一個包含monoid的applicative函數來「查看」執行。然而,有時候我根本不關心這個部分,所以幺半羣的選擇是不相關的,因爲它永遠不會被消耗。我已經簡化我有什麼到:使用約束類型和類型族具有「受限制」的約束

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE ConstraintKinds #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE TypeFamilies #-} 

import GHC.Exts 

class Render a b where render :: a -> b 
instance Render a() where render = const() 

class Merge a where 
    type Renderer a b :: Constraint 
    merge :: Renderer a b => a -> b 

data Foo = Foo Bool 

instance Merge Foo where 
    type (Renderer Foo) m = (Render Bool m) 
    merge (Foo b) = render b 

Render用於各種a轉換且爲單一bMerge是我的實際仿函數的一個很大的簡化,但重點是它包含一個類型族/約束,我的目的是明確指定什麼RenderMerge需要。現在

,我可能要「跑」的Merge,但丟棄的觀點,這是類似於這樣的:

runFoo :: Merge a => a -> Int 
runFoo x = case merge x of() -> 5 

但因爲這將失敗:

無法推斷(Renderer a())從使用merge

我選擇()我的幺因爲˚F產生或者a,我們有一個Render a()的實例。所以如果有一種方法可以說Merge a只是意味着收集Render約束,那麼這將工作正常。當然,Merge a比這更一般 - 它可以添加任意約束,這就解釋了編譯錯誤。

有沒有辦法實現我想要的沒有更改runFoo的簽名?

+0

是否'Renderer'總是正好包括一個'Render'? – 2013-01-04 13:55:21

+0

@Tinctorius - 不,通常取決於'Foo'字段中不同類型的數量 – ocharles

+0

'Merge'沒有'b'作爲參數嗎? –

回答

6

,如果你有很多這種情況下,這可能不是規模,但這個工程:

class Renderer a() => Merge a where 
    ... 
+0

我沒有考慮過。我可以閱讀這個約束,因爲''合併'應該至少支持用'()'monoid'進行渲染。但是,這會產生'UndecidableInstances'。 – ocharles

+0

「UndecidableInstances不是一個危險的標誌,它永遠不會導致類型檢查程序接受出錯的程序。使用該標誌的唯一不良後果就是類型檢查器可能告訴我們,由於上下文堆棧深度限制,它無法確定我們的程序是否打好了類型。「 http://okmij.org/ftp/Haskell/TypeClass.html#undecidable-inst-defense –

+0

我知道,我已經在其他3個地方使用它了)但理想情況下,我喜歡找到不需要它的解決方案,即使純粹由於學術原因。我可能會接受這個答案,只是讓這個問題開放一段時間。這確實是一種享受! – ocharles