2013-08-16 57 views
4

我hvae只是invended的Maybe以下替代定義:如何使Maybe工作的這個備選定義?

type Maybe' a = forall b. (b -> (a -> b) -> b) 

just :: a -> Maybe' a 
just a = \d f -> f a 

nothing :: Maybe' a 
nothing = const 

bind :: Maybe' a -> (a -> Maybe' b) -> Maybe' b 
bind ma f = ma nothing (\a -> f a) 

問題是我不能添加以下實例聲明

instance Monad (Maybe') where 
    return = just 
    a >>= f = bind a f 

的錯誤信息是:

Type synonym Maybe' should have 1 argument, but has been given none 

有什麼方法可以解決?

+2

Ahem,抱歉是那個僧侶,但你還沒有發明一個新的也許,你已經重新發現了它的**教會編碼** - 例如見這裏 - https://gist.github.com/rampion/2176199 –

+0

我用Google搜索「教會編碼也許」的方式獨立提出了相同的答案。我沒有偷你的答案。 – nponeccop

+2

一個有趣的事實:被視爲一個命題,你的'Maybe(A)'是'FALSE - > NOT(NOT(A))',它與'TRUE OR'相同' - 一個單位類型的析取' )'並鍵入'A'。 –

回答

8

如果將其包裝在newtype中,則只能將其設置爲Monad的實例。您還可以使用PolymorphicComponents擴展(的RankNTypes較弱的形式)普遍量化b

{-# LANGUAGE PolymorphicComponents #-} 

newtype Maybe' a = Maybe' { unMaybe' :: forall b. (b -> (a -> b) -> b) } 

just :: a -> Maybe' a 
just a = Maybe' (\d f -> f a) 

nothing :: Maybe' a 
nothing = Maybe' const 

bind :: Maybe' a -> (a -> Maybe' b) -> Maybe' b 
bind ma f = Maybe' (unMaybe' ma const (\a -> unMaybe' (f a))) 

instance Monad Maybe' where 
    return = just 
    (>>=) = bind 

你需要一個NEWTYPE是哈斯克爾類型同義詞不「粘」的原因。當Haskell試圖匹配沒有新類型的Maybe'類型簽名與Monad類型類型時,它根本沒有看到Maybe',而是看到原始底層函數類型。

Haskell使用「主體類型」來確保每種類型都具有正常形式。基本功能的正常形式是:

(->) b ((->) ((->) a b) b) 

類型同義詞不改變一個類型的正常形式,但newtypes做。具體而言,在這種情況下,newtype正在重新安排類型,以便正常形式現在將a作爲最後一個類型參數,如Monad實例所需。

+2

'PolymorphicComponents'並不比'RankNTypes'弱,至少在GHC中(實際上它們是同一個擴展名的兩個名稱 - 「Rank2Types」是它的另一個名稱,過去它們的處理方式不同)。請注意,對於這種新類型,構造函數'Maybe'具有rank-2類型。 – shachaf

+0

+1。然而,這看起來有點難看,因爲那些'Maybe'和'unMaybe'。有沒有很好的理由,這是不允許的?你能解釋一下嗎?另外,我以任何方式使用'RankNTypes'和'ExistentialQuantification'。 –

+0

@EarthEngine我不知道如何解釋這一點,但我更新了我的答案,給我最好的解釋爲什麼你需要新類型的嘗試。 –

6

類型同義詞不是類型。通過newtype,您可以獲得* -> *類型,並且您可以獲得類型同義詞。所以你的問題現在被簡化爲爲什麼類型同義詞不是一流的。

答案可能是因爲第一類同義詞會造成太多含糊之處,並且在簡單情況下不可能進行類型推斷。

type First a b = (a, b) 
type Second a b = (b, a) 
type Both a = (a, a) 

如果我們可以定義Functor (First a)Functor (Second a)Functor (Both a)實例,則fmap (+1) (2, 3)會ambigous。

你的發明BTW被稱爲Church encoding。教會編碼任何東西都是可能的。請參閱https://gist.github.com/rampion/2176199,瞭解Haskell中幾個教會編碼的實現(對,Maybe和列表)。

1

類型同義詞不能部分應用。

類型同義詞只是幫助程序員的簡短手段,而不是實際存在的作爲Haskell語言可以討論的內容。 Haskell處理類型同義詞的唯一方法是通過「查看」它來查看右側的類型。參數只是給你一種「宏語言」。因此Maybe' aforall b. (b -> (a -> b) -> b)完全等價。它的行爲就像你寫forall b. (b -> (a -> b) -> b)一樣。但是什麼是Maybe'本身沒有爭論呢? Haskell無法將其作爲Maybe'來處理,它必須將其替換爲其他內容。但是什麼?如果它意味着什麼,它將必須是類似於\a ~> (forall b. (b -> (a -> b) -> b),其中我使用\a ~> ...作爲類型級lambda的僞語法;從一個類型到另一個類型的任意函數。我不得不爲此編寫語法的原因是因爲Haskell沒有這個語法,而且它沒有語法的原因是因爲它不能處理完全通用的類型級函數。

我不確定支持任意類型lambda表達式(類型構造函數和類型系列實際上是非常有限的形式)實際上是不可能的,但它肯定是非常困難的。所以類型同義詞不能被部分應用。

要得到的東西,可以由Monad一個實例(這需要一些可以應用於類型做一個類型 - 樣* -> *東西),你需要使用datanewtype創建一個類型構造。類型同義詞不能用於此目的。