Je veux faire un constructeur intelligent intelligent pour les données.MAP avec une certaine contrainte sur les types de relations de paires de clé / de valeur. C'est la contrainte que j'ai essayée d'exprimer: pour chaque champ, il n'existe qu'un seul type de valeur qu'il doit être associé. Dans mon cas, il n'a aucun sens pour un champ code> code> pour mapper sur un mais je reçois l'erreur de type suivante: p> à l'aide de Je comprends pourquoi je reçois le type de malaque, mais comment puis-je exprimer cette contrainte pour que ce soit est une erreur de type temporisation-checker pour utiliser C'était m'a suggéré de par #hakell pour utiliser un L'objectif est de pouvoir écrire p> de sorte que je puisse faire de sécurité donc cela devrait donc vérifier p> mais cela doit être une erreur de temps de compilation p> édition: p> Je commence à Pensez que mes besoins spécifiques ne sont pas possibles. Utilisation de mon exemple original P> afin d'appliquer la contrainte sur maintenant, je peux écrire une instance pour la paire code> code> qui ne contient que lorsque le et j'ai les propriétés que je veux p> bytestring code>. Un champ code> vitesse code> doit planer uniquement sur un
float code> p>
-xkindsignatures code>: p>
topair code> sur un champ
non correspondant code> et
de valeur code>. p>
gadt code>, mais je n'ai pas pu le comprendre encore. P>
cartographique code> s où les invariants de clé / valeur sont respectés. p>
FOO code> et
bar code>, il doit y avoir un moyen de Différencier entre un
FOOINT code> et
FOOfloat code> au niveau de type et de la même manière pour
bar code>. Ainsi, j'ai besoin plutôt de deux gadits p>
foo code> et
bar code> sont tous deux étiquetés avec le même type P>
xs = [fooint, foofloat] code> car cela nécessiterait une liste hétérogène. En outre, si j'essaie de faire la carte
code> Synonyme
Tapez foobar = carte (foo?) (Bar?) Code> Je suis coincé avec une carte code> de Soit seulement
int code> types ou uniquement
float code> Types, ce qui n'est pas ce que je veux. Il cherche plutôt désespérément, à moins que la magie de classe de type puissante ne me connaisse pas. P> P>
4 Réponses :
Vous pouvez utiliser un gadt,
data Foo :: * -> * where FooInt :: Int -> Foo Int FooFloat :: Float -> Foo Float data Bar :: * -> * where BarInt :: Int -> Bar Int BarFloat :: Float -> Bar Float class Pair f b c| f b -> c where toPair :: f -> b -> c instance Pair (Foo Int) (Bar Int) ((Foo Int),Int) where toPair a (BarInt b)= (a,b) type family FooMap k :: * type instance FooMap (Foo Int) = Map (Foo Int) (Bar Int)
C'est vraiment proche de ce dont j'ai besoin. Y a-t-il un moyen de le faire sans diviser FOO en 2 types? J'ai besoin de là pour y avoir un type de foo unifié.
En fait, je ne suis pas sûr que cela fonctionne. En plus d'avoir besoin d'un type de foo unifié, je ne pense pas que je puisse écrire type foobar = carte foo bar code> puisque la barre n'a pas la sorte *
Je pense que nous pouvons faire ce travail bien pour vous, donnez-moi un peu et je vais essayer de trouver quelque chose
Pouvez-vous expliquer un peu plus sur vos types? Cela pourrait aider à produire une meilleure solution.
FOO va-t-il vraiment être la clé de carte?
FOO est vraiment un type d'énumération de style C / Java pour des champs d'un type de données de message que j'essaie de travailler avec. Chaque champ sera associé à une valeur sur la carte, mais compte tenu du type de champ, je connais déjà le type de valeur unique autorisé. Si le champ est "vitesse" par exemple, dans mon cas, je sais que la seule valeur autorisée doit être un flotteur. Mais si le champ est "NOM", la seule valeur autorisée devrait être byressing. Je souhaite pouvoir écrire un constructeur de sécurité pour la carte afin que ces invariants détiennent et sont vérifiés à l'heure de la compilation.
Cela semble être une étape possible dans la bonne direction, mais ne satisfait pas vraiment aux exigences de ma question. Nommément, je ne peux pas écrire [barint 1, barfloat 2] code> car leurs types sont
barre int code> et
bar flottant code> respectivement et une liste doit être homogène. J'ai besoin de ma carte pour contenir des touches avec des constructeurs de types
foins code> et
foofloat code> ainsi que les valeurs correctes avec les constructeurs de type
Barint code> et
Barfloat < / code>. Je commence à penser que cela pourrait ne pas être possible ...
Lorsque j'ai lu cela pour la première fois, j'ai essayé de résoudre le problème de forcer les erreurs de compilation dans les cas requis, mais quelque chose semblait faux. J'ai ensuite essayé une approche avec plusieurs cartes et une fonction de levage, mais quelque chose me harcelait toujours. Cependant, lorsque je me suis rendu compte que essentiellement ce que vous essayez de faire est de créer une forme d'enregistrement extensible, cela me rappelait un paquet très cool que j'avais conscient de quelques mois il y a quelques mois: le paquet de vinyle (disponible sur Hackage ). Cela peut être exactement ou non les effets que vous étiez après, et cela nécessite GHC 7.6, mais voici un exemple adapté de README :
test2Casted :: Rec '["speed" ::: Float] test2Casted = cast test2
Une version ancienchool à l'aide de dynamique et typable et de fonds de fonds. Pour le garder en sécurité, il vous suffit de ne pas exporter les choses en abstraction-rompant comme le constructeur sm code> et la smkey
Smkey code> Typeclass.
{-# LANGUAGE DeriveDataTypeable, MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances, FlexibleInstances #-}
module Main where
import qualified Data.Map as M
import Data.Dynamic
import Data.Typeable
data SpecialMap = SM (M.Map String Dynamic)
emptySM = SM (M.empty)
class (Typeable a, Typeable b) => SMKey a b | a -> b
data Speed = Speed deriving Typeable
data Name = Name deriving Typeable
data ID = ID deriving Typeable
instance SMKey Speed Float
instance SMKey Name String
instance SMKey ID Int
insertSM :: SMKey k v => k -> v -> SpecialMap -> SpecialMap
insertSM k v (SM m) = SM (M.insert (show $ typeOf k) (toDyn v) m)
lookupSM :: SMKey k v => k -> SpecialMap -> Maybe v
lookupSM k (SM m) = fromDynamic =<< M.lookup (show $ typeOf k) m
-- and now lists
newtype SMPair = SMPair {unSMPair :: (String, Dynamic)}
toSMPair :: SMKey k v => k -> v -> SMPair
toSMPair k v = SMPair (show $ typeOf k, toDyn v)
fromPairList :: [SMPair] -> SpecialMap
fromPairList = SM . M.fromList . map unSMPair
{-
*Main> let x = fromPairList [toSMPair Speed 1.2, toSMPair ID 34]
*Main> lookupSM Speed x
Just 1.2
-}
Cette réponse est arrivée la plus proche de ce dont j'ai besoin. S'il était possible de garder vitesse code>
nom code> et
ID code> sous un type, ce serait exactement correct.
Avec des types de données, vous pouvez trier de faux qu'ici. Ils seront toujours différents types aussi i>, mais ils seront également déclarés comme des valeurs uniformes au niveau de la valeur. Je n'ai pas 7,6 sur ma boîte, alors je n'y suis pas allé :-)
De plus, je ne pense pas que cela ajoute quelque chose d'utile à cette solution, ni même réduit le code, tout a dit :-(
Je ferais un type de type opaque avec des getters et des setters.
module Rec (Rec, getSpeed, getName, getID, setSpeed, setName, setID, blank) where data Rec = R { speed :: Maybe Double; name :: Maybe String; id :: Maybe Int } getSpeed :: Rec -> Maybe Double getSpeed = speed setSpeed :: Double -> Rec -> Rec setSpeed s r = r { speed = s } blank = R { speed = Nothing, name = Nothing, id = Nothing }
Avez-vous essayé Signatures type explicite ? Juste curieux.
Pourquoi ne pas utiliser une famille de données. Ensuite, le type de carte peut être attaché au type de clé.
Ces questions de mienne sont similaires et pourraient aider. Stackoverflow.com/questions/14949021/... Stackoverflow.com/ Questions / 14918867 / Trouble-avec-Datakinds
Une question de simpleston: si la correspondance est une à une, pourquoi ne pas utiliser une seule définition de données simple
champ de données = flotteur de vitesse | Nom bytestring | Id int code>? Vous pouvez simplement écrire
test1 = [vitesse 1.0, ID 2] code>, mais
test2 = [vitesse (1 :: int)] code> donnerait une erreur de compilation. Que voulez-vous faire ce serait impossible de cette façon? Avez-vous vraiment besoin d'avoir des champs non conseillants?
@Willness: Je dois être capable de rechercher la valeur code> liée au champ code> code>, et il doit être similaire à
carte code> parce que j'ai besoin Diffusion
non instantané code> s. Si le champ
code> contient toutes les informations, il défait le point de recherches car je vais devoir connaître la valeur que le champ
code> contient.
Si vous n'avez que trois types de champ, pourquoi ne pas avoir trois clés de chaîne, ou trois INTS même (1,2 et 3), c'est-à-dire une certaine énumération, pour représenter un champ non déterminé. Ensuite, vous pouvez avoir une fonction de constructeur
mkfield 1 vitesse = vitesse val; Mkfield 2 Nom = Nom du nom; mkfield 3 id = id id code> pour construire des valeurs complètes. .... Je vois, les types ...
@Willness: C'est un exemple simplifié. En fait, j'ai ~ 30 champs, c'est pourquoi je recherche une solution élégante pour que cela facilite le fonctionnement.
Je vois. Vous pouvez appuyer sur
peut-être code> dans les champs,
champ de données = vitesse (peut-être flotter) | ... code> et avoir
rien code> pour représenter les valeurs non continentales.
C'est le problème que j'essayais de résoudre avec une carte
code>. Je veux éviter d'avoir une structure d'enregistrement avec ~ 30 entrées, tout
peut-être champ code>. Avec une carte
code>, je n'ai à vous soucier que des entrées que j'utilisais réellement et que je laisse la sémantique de la recherche s'inquiéter de si l'entrée existe ou non.
Laissez-nous Continuer cette discussion en chat