一个基本的Haskell问题:
我想在Haskell中“标记函数”:我有一个列表
scheme = [ f1, f2, f3, ... ]
是由一些简单的函数构建的,其中一些函数属于某个组:
f1 :: a -> a
f1 a = ...
f2 :: a -> a -- "belongs to group"
f2 a = ...
f3 :: a -> a
f3 a = ...
f4 :: a -> a -- "belongs to group"
f4 a = ...
...
我想创建一个较小的列表,只包含属于该子组的函数:
filter belongsToGroup scheme
在Java中,函数将是Function类的子类,其中一些函数实现了一个空的标记接口FunctionGroup。然后可以使用运算符instanceof
我试图理解如何在Haskell中模仿这种行为(研究“类型类”),但没有成功。
任何帮助?
答案 0 :(得分:7)
Haskell积极阻止您使用类型系统逃生舱口。 (一个instanceof
- 类似的构造会破坏一些不错的类型系统属性,例如参数化。)你最有可能想要使用这种类型:
type TaggedFunction a b = (a -> b, Bool)
第一个组件只是您要使用的常规函数,第二个组件是函数属于该组时的True
,否则为False
。
然后您按照以下方式过滤TaggedFunction
:filter snd tfs
答案 1 :(得分:6)
解决此问题的一种方法是创建表示这些函数的数据类型。
data TaggedFunction a = UsefulFunction (a -> a)
| UselessFunction (a -> a)
f1 :: TaggedFunction a
f1 = UsefulFunction $ \x -> x
f2 :: TaggedFunction a
f2 = UselessFunction $ \x -> x
isUseful :: TaggedFunction a -> Bool
isUseful (UsefulFunction _) = True
isUseful _ = False
main :: IO ()
main = do
let fs = [f1, f2, f1, f2]
useful = filter isUseful fs
print $ (_f $ head useful) 4
这种方法很容易扩展,可以包含两个以上的组,甚至可以使用例如两个组自动生成。模板Haskell。
经过一段时间的游戏,我更喜欢TaggedFunction
的重构。
data TaggedFunction a = Group1 { _f :: a }
| Group2 { _f :: a }
| Group3 { _f :: a }
f1 :: TaggedFunction (a -> a)
f1 = Group1 $ \x -> x
f2 :: TaggedFunction (a -> a)
f2 = Group2 $ \x -> x
isGroup :: Int -> TaggedFunction a -> Bool
isGroup 1 (Group1 _) = True
isGroup 2 (Group2 _) = True
isGroup 3 (Group3 _) = True
isGroup _ _ = False
main :: IO ()
main = do
let fs = [f1, f2, f1, f2]
useful = filter (isGroup 1) fs
print $ length useful
print $ (_f $ head useful) 4
输出:
λ> main
2
4
请注意,isGroup
现在不是全部(我不喜欢),但就本示例而言,它比单个isGroupN
函数更方便。