几乎是标题,但让我们详细说明:
假设我有一些类型类SomeTypeClass
和不同类型A
,B
,C
,每个类型都有一个实例。
让我们进一步假设我有一个功能
fun :: (SomeTypeClass a) => Maybe a -> Result
对于某些类型常量Result
。
表达式
fun (Nothing :: Maybe A)
fun (Nothing :: Maybe B)
fun (Nothing :: Maybe C)
以某种方式产生不同的结果?
(可能是某些编译器扩展为fun
提供了不同的实现,具体取决于参数类型等。)
答案 0 :(得分:5)
当然,Result
= String
和SomeTypeClass a
= (Monoid a, Show a)
:
import Data.Foldable
doSomething :: (Show a, Monoid a) => Maybe a -> String
doSomething = show . fold
doSomething (Nothing :: Maybe String) == "\"\""
doSomething (Nothing :: Maybe [Int] == "[]"
doSomething (Nothing :: Maybe (Product Int)) == "Product {getProduct=1}"
doSomething (Nothing :: Maybe (Sum Int)) == "Sum {getSum=0}"
当然不是唯一的例子,但可能是最简单的(也就是说,至少类似于你在实际代码中可能会遇到的东西)。
答案 1 :(得分:2)
我能想出来实现这一目标的最简单方法是以下黑客攻击:
{-# LANGUAGE ScopedTypeVariables #-}
data A = A
data B = B
class SomeClass a where
doSomething :: a -> String
instance SomeClass A where
doSomething _ = "always a"
instance SomeClass B where
doSomething _ = "always b"
instance SomeClass a => SomeClass (Maybe a) where
doSomething (Just x) = doSomething x
doSomething Nothing = doSomething (undefined :: a)
main = print (doSomething (Nothing :: Maybe A), doSomething (Nothing :: Maybe B), doSomething (Just A))
您可以使用undefined
数据类型绕过丑陋的data Proxy a = Proxy
。我不确定这在实践中有多大用处,因为您无法检查A
和B
的实例中的输入。
编辑:这是代理版本,您可以在Just a
处检查输入:
{-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances, ScopedTypeVariables #-}
data A = A Int
data B = B Int
data Proxy a = Proxy
class SomeClass a where
doSomething :: a -> String
instance SomeClass A where
doSomething (A x) = "always A with " ++ show x
instance SomeClass B where
doSomething (B x) = "always B with " ++ show x
instance SomeClass (Proxy A) where
doSomething Proxy = "proxy A(Nothing)"
instance SomeClass (Proxy B) where
doSomething Proxy = "proxy B(Nothing)"
instance (SomeClass a, SomeClass (Proxy a)) => SomeClass (Maybe a) where
doSomething (Just x) = doSomething x
doSomething Nothing = doSomething (Proxy :: Proxy a)
main = print (doSomething (Nothing :: Maybe A), doSomething (Nothing :: Maybe B), doSomething (Just $ A 2))
虽然感觉更像是黑客(UndecidableInstances
yikes)
答案 2 :(得分:1)
作为参考最基本的例子,我发现:
module TestNothings where
class SomeClass a where
doSomething :: Maybe a -> Int
newtype A = A Int deriving (Eq, Show)
newtype B = B Int deriving (Eq, Show)
newtype C = C Int deriving (Eq, Show)
instance SomeClass A where
doSomething (Just (A i)) = i
doSomething Nothing = 0
instance SomeClass B where
doSomething (Just (B i)) = i
doSomething Nothing = 1
instance SomeClass C where
doSomething (Just (C i)) = i
doSomething Nothing = 2
答案 3 :(得分:0)
添加另一个类型类助手可以避免{@ 1}}扩展可以避免如果我们引入另一个类型类助手,其默认ScopedTypeVariables
实现调用ad-hoc“overloaded”fun
使用的情况他们只对类型推断的论证:
Nothing
添加新类型后,可以使用新的type Result = String
data A = A
data B = B
class SomeClass a where
foo :: a -> Result
instance SomeClass A where
foo _ = "A"
instance SomeClass B where
foo _ = "B"
class SomeClass a => Fun a where
fun :: Maybe a -> Result
fun (Just a) = foo a
fun a = funNothing a
funNothing :: Maybe a -> Result
instance Fun A where
funNothing _ = "No A"
instance Fun B where
funNothing _ = "No B"
main = do
putStrLn $ fun (Just A)
putStrLn $ fun (Just B)
putStrLn $ fun (Nothing :: Maybe A)
putStrLn $ fun (Nothing :: Maybe B)
实例轻松扩展乐趣。
答案 4 :(得分:0)
我可能错了,但我从以下方面理解:
要实现这样的函数fun
,您需要ad-hoc多态,即对于不同的输入类型,您需要a
的不同实现。无法从Nothing
中获得SomeTypeClass
f :: Maybe a -> Result
的正确类型(即稀薄的空气),答案将是否。
但是,如果您的类型类fun
具有以下功能:
f
然后fun = f
可以与f
相同:
cd wordpress
sudo find . -type d -exec chmod 0755 {} \;
sudo find . -type f -exec chmod 0644 {} \;
现在,您可以通过在实例中实现define( 'FS_METHOD', 'direct' );
的不同版本来实现ad-hoc多态性。即答案是是,但您必须在类型类中实现问题的相关部分。