我有两个不同类型的签名功能:如何获得的功能特性
f :: Int -> [a] -> [a]
g :: (Int, Int) -> [a] -> [a]
第一个参数确定功能运行在列表的长度。例如,f
可能在长度为p-1
的列表上运行,并且g
分别在第一自变量p
和(p,e)
上的长度为p^(e-1)
的列表上操作。
我使用f
和g
作为需要知道此长度函数(h
的第一个参数)的另一个函数h :: Int -> ([a] -> [a]) -> [a] -> [a]
的参数。我觉得自己目前做的是:
\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'
以预期的方式。我期望这个问题在之前已经“解决”了,但我不知道我应该在寻找什么。
为什么你需要这些混乱的“长度来操作”呢?听起来好像分割列表并将某些部分传递给在列表上运行的函数会更好。 – leftaroundabout
我很难理解你在问什么。在函数上不可能进行模式匹配,在funcToLen的定义中,第一个模式总是会成功的,在第二个例子中,您使用'Either'作为构造函数(你的意思是'Left'/'Right'?)无论哪种方式,都有很多随机的单字符变量存在,这很难遵循。我很难理解为什么这是必要的。无论如何,既然你有两种不同的类型,并且需要对它们进行模式匹配,使用'Either'似乎是最好的选择。 –
@leftaroundabout总之,数学。列表输入是张量,“f”和“g”在该张量的一个维度上操作。函数“h”将“f”和“g”从一维提升到多维。其结果是'f'和'g'最终只能在列表的几个元素上工作,间隔一个步幅和一个偏移量。 'h'需要知道'f'的维数,以便知道运行'f'的次数(以及用什么步长/偏移量)。 – crockeea