在Haskell中标记函数

时间:2013-12-13 21:48:41

标签: haskell

一个基本的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中模仿这种行为(研究“类型类”),但没有成功。

任何帮助?

2 个答案:

答案 0 :(得分:7)

Haskell积极阻止您使用类型系统逃生舱口。 (一个instanceof - 类似的构造会破坏一些不错的类型系统属性,例如参数化。)你最有可能想要使用这种类型:

type TaggedFunction a b = (a -> b, Bool)

第一个组件只是您要使用的常规函数​​,第二个组件是函数属于该组时的True,否则为False

然后您按照以下方式过滤TaggedFunctionfilter 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函数更方便。