dum*_*mb0 2 polymorphism haskell
是否可以在Haskell98中编码或使用以下函数扩展f?
f :: (a -> b) -> (b -> a) -> c -> d
where (c,d) :: (a,b) || (c,d) :: (b,a)
Run Code Online (Sandbox Code Playgroud)
我试图创建一些通用函数来在任何两种类型之间进行转换a,b但是两者都有点困难.然而,它们是由第一个参数立即设置的a ->b,所以我希望这是可能的.任何指导表示赞赏......
谢谢!
[编辑]
我看到它的方式,我的问题归结为haskell的类型系统是否支持or关键字...因为我的功能的直观签名是:f :: (a->b) -> (b->a) -> a -> b or (a->b) -> (b->a) -> b -> a...
正如alecb解释的那样,它不能以你的签名建议的方式完成,至少通过普通手段(它需要在运行时检查类型).你可能会喜欢另一种是异和棱镜的lens.Iso如果你的转换函数是完全和双射的,那么符合条件; 如果其中一个函数是偏的,你可以使用一个Prism.这是一个一次性的例子:
import Control.Lens
import Text.ReadMaybe
stringInt :: Prism' String Int
stringInt = prism' show readMaybe
Run Code Online (Sandbox Code Playgroud)
GHCi> "3" ^? stringInt
Just 3
it :: Maybe Int
GHCi> 3 ^. re stringInt
"3"
it :: String
Run Code Online (Sandbox Code Playgroud)
假设我们有两个转换函数:
i2s :: Int -> String
s2i :: String -> Int
Run Code Online (Sandbox Code Playgroud)
会是什么类型的g = f i2s s2i?我们想g 1成为一个法律表达,也是g "one".所以g接受Int和String.这给我们留下了三个选择:
g是一个完全多态的函数 - 也就是说,它的第一个参数是类型a.所以,g True和g [1,2,3]也是合法的.如此通用的函数与转换无关,你可以证明这种函数不能做任何有趣的事情(例如,类型的函数a -> Int必须是常量)
g期望某个类型类的参数 - 例如,show是一个只接受受限制的类型组(包括Int和String)的函数.但是现在你的函数不是完全多态的 - 它只适用于这个受限制的类型组.
我们可以为此任务定义新的数据类型:
data IntOrString = I Int | S String
-- the type signature is slightly different
f :: (Int -> String) -> (String -> Int) -> IntOrString -> IntOrString
f i2s s2i (I n) = S $ i2s n
f i2s s2i (S s) = I $ s2i S
Run Code Online (Sandbox Code Playgroud)
虽然这个函数在某些情况下可能很有用,但它不再是通用的(它支持的唯一对是Int和String).
所以答案是 - 您可以使用此类型签名定义函数,但它仅适用于特定类型或类型类.
编辑:不,不支持类型的功能a -> b where a is Int or String.这需要动态语言或支持子类型的静态语言.
我怀疑可以直接做你想做的事,但你可以使用一些解决方法:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
class Converter a b c where
($$) :: a -> b -> c
data Conv a b = Conv a b
instance Converter (Conv (a -> b) (b -> a)) a b where
($$) (Conv f _) = f
instance Converter (Conv (a -> b) (b -> a)) b a where
($$) (Conv _ g) = g
intToString :: Int -> String
intToString = show
stringToInt :: String -> Int
stringToInt = read
printString :: String -> IO ()
printString = print
printInt :: Int -> IO ()
printInt = print
main = do
let convert = Conv intToString stringToInt
printString $ convert $$ (12345 :: Int)
printInt $ convert $$ "12345"
Run Code Online (Sandbox Code Playgroud)
我相信这足够接近你想要的.唯一的区别是强制$$运营商,但这是不可避免的.
更新:你甚至可以删除特殊Conv结构并使用普通元组:
instance Converter (a -> b, b -> a) a b where
($$) (f, _) = f
instance Converter (a -> b, b -> a) b a where
($$) (_, g) = g
-- ...
printString $ (intToString, stringToInt) $$ (12345 :: Int)
printInt $ (intToString, stringToInt) $$ "12345"
Run Code Online (Sandbox Code Playgroud)
我认为这更接近你的要求.