我有兩個不同類型的簽名功能:如何獲得的功能特性
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