2014-10-29 196 views
8

對不起,我無法想象任何更好的問題標題,所以請先閱讀。試想一下,我們有一個封閉式的家庭映射每一種類型,以它的相應Maybe除了maybes自己:封閉式家庭和奇怪的功能類型

doMagic :: a -> Family a 
doMagic = undefined 

exampleA = doMagic $ Just() 
exampleB = doMagic $() 

在GHCI擺弄它:

type family Family x where 
    Family (Maybe x) = Maybe x 
    Family x = Maybe x 

我們可以使用這種類型的家庭甚至聲明函數顯示可以評估此​​功能應用程序的類型:

*Strange> :t exampleA  
exampleA :: Maybe()  
*Strange> :t exampleB  
exampleB :: Maybe()  

問題是,是否可以提供任何實現doMagic功能除了undefined?舉個例子說,我想將每個值都包含在Just的構造函數中,但Maybes應該保持不變,我該怎麼做?我試過使用類型類,但是如果不使用封閉類型的家族,沒有寫出doMagic函數的可編譯簽名,有人可以幫我嗎?

+1

在一個動態類型語言'doMagic x = Just undefined'也將尊重類型。從理論上講,類型系統可以允許這樣做(但是這會非常有用嗎?)。順便說一句,你描述的例子,如果你根據哪個具體類型'a'做了不同的事情,在運行時需要類型信息,而Haskell被設計爲允許類型擦除(在運行時沒有類型信息)。不過,您可以使用類型類來獲得更近的東西。 – chi 2014-10-29 23:36:03

+1

此外,這個問題看起來與「封閉類型家族存在的類型的_free定理是什麼?」有關。 – chi 2014-10-29 23:41:12

回答

8

您可以使用另一個封閉類型家族來區分Maybe xx,然後您可以使用另一個類型類別爲這兩種情況提供doMagic的單獨實現。快速和骯髒的版本:

{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, 
    FlexibleInstances, UndecidableInstances, ScopedTypeVariables #-} 

type family Family x where 
    Family (Maybe x) = Maybe x 
    Family x = Maybe x 

data True 
data False 

type family IsMaybe x where 
    IsMaybe (Maybe x) = True 
    IsMaybe x = False 


class DoMagic a where 
    doMagic :: a -> Family a 

instance (DoMagic' (IsMaybe a) a (Family a)) => DoMagic a where 
    doMagic = doMagic' (undefined :: IsMaybe a) 


class DoMagic' i a r where 
    doMagic' :: i -> a -> r 

instance DoMagic' True (Maybe a) (Maybe a) where 
    doMagic' _ = id 

instance DoMagic' False a (Maybe a) where 
    doMagic' _ = Just 


exampleA = doMagic $ Just() 
exampleB = doMagic $() 
+0

這真是太神奇了。 – dfeuer 2014-10-31 06:03:35

4

您可以排序使一個doMagic功能。不幸的是,這個家庭的封閉性並不能真正幫助你。這裏是一個開始會是什麼樣

{-# LANGUAGE TypeFamilies #-} 

type family Family x where 
    Family (Maybe x) = Maybe x 
    Family x = Maybe x 

class Magical a where doMagic :: a -> Family a 
instance Magical (Maybe a) where doMagic = id 
instance Magical() where doMagic = Just 

你可以看到它在ghci中工作,就像你問:

*Main> doMagic $ Just() 
Just() 
*Main> doMagic $() 
Just() 

那麼,爲什麼我說這是一起蹣跚?嗯,你可能已經注意到,這兩個實例提供不包括非常多的類型Haskell的生態系統:

*Main> doMagic $ True 
<interactive>:3:1: 
    No instance for (Magical Bool) arising from a use of ‘doMagic’ 
    In the expression: doMagic 
    In the expression: doMagic $ True 
    In an equation for ‘it’: it = doMagic $ True 

所以一個人必須要爲每個感興趣的類型(構造函數)提供實例。事實上,甚至連不連貫的例子 - 許多這樣的問題都可以被擊敗的俱樂部 - 在這裏有所幫助;如果試圖寫

instance Magical (Maybe a) where doMagic = id 
instance Magical a where doMagic = Just 

編譯器正確地抱怨說,畢竟我們不知道,完全態實例實際上有正確的類型。關於不連貫實例的事情是編譯器不告訴我們,僅僅因爲這是所選實例,其他實例肯定是不適用。所以我們有可能在某個時候選擇完全多態的實例,後來才發現我們真的是幕後的Maybe,然後我們圍繞一些東西包裝了太多的Maybe層。不幸的。

目前沒有太多可以做到這一點。目前封閉式家庭並不能提供所有可能希望獲得的知識。或許有一天,GHC將提供一種機制,使封閉型家庭在這方面更有用,例如類型不平等約束,但我不會屏住呼吸:如何提供這些有用的信息是一個研究問題,沒有聽到任何有關人們處理它的傳言。