我有两种不同类型签名的函数:
f :: Int -> [a] -> [a]
g :: (Int, Int) -> [a] -> [a]
第一个参数确定函数操作列表的长度。例如,f
可能对长度为p-1
的列表进行操作,g
对长度为p^(e-1)
的列表进行操作,分别为第一个参数p
和(p,e)
我使用f
和g
作为另一个函数h :: Int -> ([a] -> [a]) -> [a] -> [a]
的参数,它需要知道这个长度函数(h
的第一个参数)。我现在所做的是:
\p -> h (p-1) (f p)
\(p,e) -> h (p^(e-1)) (g (p,e))
我将h
与f
和g
结合使用的所有地方。这种重复是容易出错和杂乱的。
目标是找到一种避免将长度参数传递给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'
的参数)。相反,我必须剥离元组。我正在寻找清理方法,以便我不必在任何地方复制长度函数,但也允许我使用函数f
和g'
以预期的方式。我希望这个问题已经解决了#34;以前,但我不太清楚我应该寻找什么。
答案 0 :(得分:1)
如果您创建一个计算c
的函数p^e-1
,则有效地将此操作与f
和g
解耦:
c :: (Int, Int) -> Int
c (p, e) = p ^ (e - 1)
您可以将f
和g
合并到同一个功能中(只需删除g
)。如果必须将元组转换为Int
,则使用c
。
h
的实现也很简单,不包含重复的代码。