J'ai fonctions avec deux signatures de type différents:Comment obtenir les propriétés des fonctions
f :: Int -> [a] -> [a]
g :: (Int, Int) -> [a] -> [a]
Le premier paramètre détermine la longueur de la liste que la fonction fonctionne sur. Par exemple, f
peut fonctionner sur des listes de longueur p-1
et g
fonctionne sur des listes de longueur p^(e-1)
pour les premiers arguments p
et (p,e)
respectivement.
J'utilise f
et g
comme arguments à une autre fonction h :: Int -> ([a] -> [a]) -> [a] -> [a]
qui a besoin de connaître cette fonction de la longueur (h
« premier argument). Que faire est actuellement je me trouve:
\p -> h (p-1) (f p)
\(p,e) -> h (p^(e-1)) (g (p,e))
partout où j'utiliser h
en combinaison avec f
et g
. Cette duplication est sujette aux erreurs et désordonnée.
L'objectif est de trouver un moyen d'éviter de passer l'argument longueur à h
. Au lieu de cela, h
devrait être en mesure de déterminer la longueur elle-même en fonction de l'argument de la fonction.
Un non-solution serait de changer la définition de 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)
Cela présente plusieurs inconvénients:
- Je dois changer le premier argument de
f
, puis ignorer la deuxième partie du tuple - Lorsque j'utilise réellement
h'
avecf'
, je dois créer un argument fictif pour la deuxième partie du tuple - Le plus important,
funcToLen
ne fonctionne pas parce que je ne peux pas correspondre à des noms de fonction.
Une autre solution qui fonctionne réellement est d'utiliser 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
Cela a aussi quelques inconvénients:
- La fonction de la longueur est dupliqué pour chaque motif de
f'
etg'
- Les signatures de type
f'
,g
'eth'
sont tous plus laides - Je ne peux pas utiliser immédiatement
f'
etg'
par leurs propres moyens (c.-à-d. pas comme arguments àh'
). Au lieu de cela, je dois décoller le tuple.
Je cherche des moyens pour nettoyer afin que je n'ai pas dupliquer la fonction de la longueur partout, mais me permet également d'utiliser les fonctions f
et g'
de la manière attendue. Je pense que ce problème a déjà été "résolu", mais je ne sais pas exactement ce que je devrais rechercher.
Pourquoi avez-vous exactement besoin de ce passage désordonné de "longueurs à opérer" de toute façon? On dirait qu'il vaudrait beaucoup mieux diviser la liste et passer certaines parties aux fonctions qui fonctionnent sur toute la liste. – leftaroundabout
J'ai de la difficulté à comprendre ce que vous demandez. Il n'est pas possible de faire correspondre les fonctions à des fonctions, et dans votre définition de 'funcToLen', le premier modèle réussira toujours, et dans le second exemple, vous utilisez' Sither' comme constructeur (vouliez-vous dire 'Left'/'Right'?) De toute façon, avec tant de variables aléatoires d'un caractère qui traînent, c'est assez difficile à suivre. J'ai du mal à comprendre pourquoi cela serait nécessaire. Quoi qu'il en soit, puisque vous avez deux types différents, et que vous avez besoin de faire correspondre les modèles, utiliser 'Sither' semble être le meilleur choix. –
@leftaroundabout En un mot, maths. L'entrée de liste est un tenseur, et 'f' et' g' agissent sur une dimension de ce tenseur. La fonction 'h' 'soulève'' f' et 'g' d'une dimension vers plusieurs dimensions. Le résultat est que 'f' et' g' finissent par travailler sur quelques éléments de la liste, espacés par une foulée et avec un décalage. 'h' a besoin de connaître la dimension de' f' pour savoir combien de fois (et avec quelle foulée/décalage) exécuter 'f'. – crockeea