如何获取函数的属性

时间:2014-06-12 22:23:09

标签: haskell higher-order-functions

我有两种不同类型签名的函数:

f :: Int -> [a] -> [a]
g :: (Int, Int) -> [a] -> [a]

第一个参数确定函数操作列表的长度。例如,f可能对长度为p-1的列表进行操作,g对长度为p^(e-1)的列表进行操作,分别为第一个参数p(p,e)

我使用fg作为另一个函数h :: Int -> ([a] -> [a]) -> [a] -> [a]的参数,它需要知道这个长度函数(h的第一个参数)。我现在所做的是:

\p -> h (p-1) (f p)
\(p,e) -> h (p^(e-1)) (g (p,e))

我将hfg结合使用的所有地方。这种重复是容易出错和杂乱的。

目标是找到一种避免将长度参数传递给h的方法。相反,h应该能够根据函数参数确定长度本身。

一个非解决方案是将f的定义更改为:

f' :: (Int, Int) -> [a] -> [a]
f' (2,_) = previous def
f' (p,_) = previous def

funcToLen :: ((Int, Int) -> [a] -> [a]) -> (Int, Int) -> Int
funcToLen f' (p,_) = p-1
funcToLen g (p,e) = p^(e-1)

h' :: (Int, Int) -> ((Int, Int) -> [a] -> [a]) -> [a] -> [a]
h' (p,e) func xs = let len = funcToLen func
                       func' = func (p,e)
                   in previous def

-- usage
(\p -> h' (p,??) f')
(\(p,e) -> h' (p,e) g)

这有几个缺点:

  • 我必须更改f的第一个参数,然后忽略元组的第二部分
  • 当我实际使用h'f'时,我必须为元组的第二部分创建一个伪参数
  • 最重要的是,funcToLen无法正常工作,因为我无法在功能名称上进行模式匹配。

另一种实际有效的解决方案是使用Either

f' :: Int -> (Int, [a] -> [a])
f' 2 xs = (1, previous def)
f' p xs = (p-1, previous def)

g' :: (Int, Int) -> Either Int ([a] -> [a])
g' (p,1) xs = (1, previous def)
g' (p,e) xs = (p^(e-1), previous def)

h' :: (Int, ([a] -> [a])) -> ([a] -> [a])
h' ef = let len = fst ef
            f = snd ef
        in previous def

这也有一些缺点:

  • f'g'
  • 的每种模式都会复制长度函数
  • f'g'和h'的类型签名都很丑陋
  • 我无法自行使用f'g'(即不作为h'的参数)。相反,我必须剥离元组。

我正在寻找清理方法,以便我不必在任何地方复制长度函数,但也允许我使用函数fg'以预期的方式。我希望这个问题已经解决了#34;以前,但我不太清楚我应该寻找什么。

1 个答案:

答案 0 :(得分:1)

如果您创建一个计算c的函数p^e-1,则有效地将此操作与fg解耦:

c :: (Int, Int) -> Int
c (p, e) = p ^ (e - 1)

您可以将fg合并到同一个功能中(只需删除g)。如果必须将元组转换为Int,则使用c

h的实现也很简单,不包含重复的代码。