2015-04-27 27 views
4

我對如何使用newtype包非常困惑。它的文檔似乎暗示這是非常強大的,但我不知道如何使用提供的功能(而不是界面)來創建我需要的一些功能。例如,我要一個功能與特徵:使用Newtype包

(Newtype n o) => (o -> o -> o) -> n -> n -> n 

(Newtype n o, Functor f) => (o -> f o) -> n -> f n 

(Newtype n o, Functor f) => (f o -> o) -> f n -> n 

寫這些與fmappackunpack是可行的組合,但我希望這是可能的,更清潔與神祕alaala'功能(或將新功能「提升」到新類型的輕微變化,而不是從新類型中「解除」它們)。如果它很重要,我特別感興趣的仿函數是Maybe[]

+0

我相信第一個最好的解決方法是使用'pack'和'unpack',使用'Data.Function'和'Data.Composition'可以簡單地用'f1 operator = pack。:on operator unpack'實現。另外兩個也很簡單:'f1 f = fmap pack。 F 。解壓縮「和」f3 f = pack「。 F 。 fmap解包「。事實上,'f2'和'f3'在'over'和'overF'兩個版本之間是中途的,這兩個版本都是在'newtype'包中用'pack'和'unpack'實現的。我會遵循作者的例子並保持簡單。 – bheklilr

+1

對Newtype(也許n)(也許o)','Newtype [n] [o]'和Newtype(o - > o')(n - > n')''有實例嗎? – crockeea

+0

你甚至可以定義這些實例嗎? – bheklilr

回答

1

根據上面的註釋,似乎可能沒有乾淨的方式來編寫我需要的函數,使用由Control.Newtype提供的hofs。但是,似乎還有其他選擇:爲 -newtypes創建實例。

newtype包一個例子:

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

import Control.Newtype 

instance (Newtype n o) => Newtype [n] [o] where 
    pack = map pack 
    unpack = map unpack 

instance (Newtype n o) => Newtype (Maybe n) (Maybe o) where 
    pack = fmap pack 
    unpack = fmap unpack 

instance (Newtype n o, Newtype n' o') => Newtype (n -> n') (o -> o') where 
    pack f = pack . f . unpack 
    unpack f = unpack . f . pack 

-- a newtype wrapper for Nums 
newtype NNum a = NNum {unNNum :: a} 
instance Newtype (NNum a) a where 
    pack = NNum 
    unpack = unNNum 

ntimes5 :: (Num a) => NNum a -> NNum a 
ntimes5 = pack sum . replicate 5 

foo :: a -> Maybe [a] 
foo = undefined 

bar :: NNum a -> Maybe [NNum a] 
bar = pack foo 

如前所述bheklilr,這需要UndecidableInstances,但它似乎並不過分要求籤名。然而,我們可以做的更好使用newtype-generics包:(當然,你總是可以在此手動導出Newtype情況下,也節省了延伸和一個進口)

{-# LANGUAGE TypeFamilies, DeriveGeneriC#-} 

import Control.Newtype 
import GHC.Generics 

instance (Newtype a) => Newtype [a] where 
    type O [a] = [O a] 
    pack = map pack 
    unpack = map unpack 

instance (Newtype a) => Newtype (Maybe a) where 
    type O (Maybe a) = Maybe (O a) 
    pack = fmap pack 
    unpack = fmap unpack 

instance (Newtype a, Newtype b) => Newtype (a -> b) where 
    type O (a -> b) = (O a -> O b) 
    pack f = pack . f . unpack 
    unpack f = unpack . f . pack 

newtype NNum a = NNum {unNNum :: a} deriving (Generic) 
instance Newtype (NNum a) 

ntimes5 :: (Num a) => NNum a -> NNum a 
ntimes5 = pack sum . replicate 5 

foo :: a -> Maybe [a] 
foo = undefined 

bar :: NNum a -> Maybe [NNum a] 
bar = pack foo 

因此這會由於出現的任何問題UndecidableInstancesFlexibleInstances現在沒有意義。類型家庭與fundeps的比較總結爲herehere。這個例子似乎是一個類型家庭提供明確勝利的例子。