2015-10-17 104 views
4

說我們有定義爲的類型種類*

data A a = A' a deriving Show 

數據類型我們有

A :: * -> * 

然後我們就可以使Functor一個實例使用的「FMAP般」的功能:

instance Functor A where fmap f (A' x) = A' (f x) 

這使我們能夠A類型的值,並使用fmap到App LY到包裹值的函數現在

Prelude> let x = A' 1 
Prelude> fmap (+1) x 
A' 2 

,如果我們定義A

data A = A' Int deriving Show 

那種A

A :: * 

因此,我們不能讓A的實例Functor -

instance Functor A where fmap f (A' x) = A' (f x) 

<interactive>:4:18: 
    Kind mis-match 
    The first argument of `Functor' should have kind `* -> *', 
    but `A' has kind `*' 
    In the instance declaration for `Functor A' 

我的問題是,是否有一種通用的方法來將數據類型爲*的數據類型的包裝值應用到只包含一個參數的數據構造函數(即類似於fmap)?它很容易編寫自定義功能:

Prelude> let myFmap f (A' x) = A' (f x) 
Prelude> let x = A' 1 
Prelude> myFmap (+1) x 
A' 2 

它也可能使ANum一個實例:

instance Num A where (+) (A' x) (A' y) = A' (x + y) -- Ignoring the warnings 
Prelude> A' 1 + A' 1 
A' 2 

這兩種方法的工作,但在那裏,我很想念更好的辦法?

回答

10

我不認爲在問題的後半部分有一個很好的通用解決方案,但我至少可以回答上半年的問題。

這是mono-traversable包的目的,它提供了MonoFunctor typeclass。對於A'實例是:如何有用,這是相對於簡單的a'map :: (Int -> Int) -> A' -> A'功能或鏡片

type instance Element A' = Int 

instance MonoFunctor a' where 
    omap f (A' i) = A' (f i) 

情況因人而異。

+1

請注意'lens'包中'iso'和可能'Wrapped'允許做類似的事情。 – mb14