【问题标题】:How to get properties of functions如何获取函数的属性
【发布时间】:2014-06-12 22:23:08
【问题描述】:

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

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'。我希望这个问题之前已经“解决”了,但我不太清楚我应该寻找什么。

【问题讨论】:

  • 究竟为什么你需要这种凌乱的“操作长度”的传递?听起来最好拆分列表并将一些部分传递给对列表all进行操作的函数。
  • 我无法理解您的要求。不可能对函数进行模式匹配,并且在您对funcToLen 的定义中,第一个模式总是会成功,而在第二个示例中,您使用Either 作为构造函数(您的意思是Left/ Right?) 不管怎样,周围有这么多随机的单字符变量,很难理解。我很难理解为什么这是必要的。无论如何,由于您有两种不同的类型,并且需要对它们进行模式匹配,因此使用 Either 似乎是最好的选择。
  • @leftaroundabout 总之,数学。列表输入是一个张量,fg 在该张量的一维上运行。函数h“提升”fg 从一维到多维。结果是fg 最终只处理列表中的几个元素,它们之间有一个步幅和一个偏移量。 h 需要知道 f 的维度,以便知道运行 f 的次数(以及步幅/偏移量)。
  • 我显然严重滥用了Eithermonad。我将用元组替换那些......
  • 您使用普通列表来表示张量?那是……大胆。 Data.Tensor 有什么问题?如果不是像这样预先构建的东西,您至少应该包装一个自定义类型来正确处理尺寸问题。

标签: haskell higher-order-functions


【解决方案1】:

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

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

您可以将fg 合并到同一个函数中(只需消除g)。当您必须将元组转换为Int 时,您使用c

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

【讨论】:

  • 我不能仅仅摆脱g,它的作用与f 完全不同。也许您可以显示更多代码?
猜你喜欢
  • 1970-01-01
  • 2017-10-22
  • 1970-01-01
  • 1970-01-01
  • 2020-07-06
  • 1970-01-01
  • 2019-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多