2009-09-01 11 views
3

discriminés Considérez quecontrainte de type dans une Union

type Foo = 
    | I of int 
    | S of string 



let test = [ I(5); I(9); I(7)] 

Il fonctionne, mais maintenant je veux « test » être de type Foo aussi et encore une liste de I ou S. Par ex

let test = L([ I(5); I(9); I(42) ]) //works! 
let test2 = L([ I(5); I(9); S("stuff") ]) //type error 
let test3 = L([ I(5); I(9); L([]) ]) //type error 

J'essaie que ..

type Foo = 
    | I of int 
    | S of string 
    | L of 'T list when 'T :> Foo 

Je sais que cela ne fonctionne évidemment pas. C'était juste quelque chose de naturel pour moi d'écrire.

Merci beaucoup d'avoir aidé !!

Répondre

2

Si I et S sont vraiment intéressants en eux-mêmes, à savoir que vous voulez savoir I listes de listes S, alors pourquoi ne pas être explicite?

type I = int 
type S = string 

type Foo = 
    | I 
    | S 
    | LI of I list 
    | LS of S list 
+0

Oui et en fait c'est ce que j'ai fait. Merci de l'avoir signalé! Mais la question était plus sur si oui ou non le système de type F # pourrait le gérer. – Stringer

7

Vous ne pouvez pas utiliser une contrainte de type générique pour 'union discriminée'. Mais vous pouvez définir le type spécifique à cette union discriminée, comme ce qui suit.

type Foo = 
    | I of int 
    | S of string 
    | L of Foo list 


// Usage 
let test = L([ I(5); I(9); S("stuff"); L([]); I(42) ]) 

Est-ce que cela répond à votre question?

5

Chris a une bonne réponse. Si c'est le cas que vous ne voulez pas de listes pour nicher, vous pouvez aussi faire

type FooAtom = 
    | I of int 
    | S of string 

type Foo = 
    | A of FooAtom 
    | L of FooAtom list 

let test = L([ I(5); I(9); S("stuff"); I(42) ]) 
let test2 = A(I(5)) 
+0

Bon appel! Je suis d'accord que le faire à ma façon vous permet de saigner les sous-listes dans la liste principale - tandis que la définition d'une deuxième union discriminée évite ce gâchis. –

+0

Merci Chris et Brian! En fait ce n'est pas exactement ce que je veux faire. Je cherche un moyen de contraindre les éléments de la liste à ne provenir que d'un type particulier comme dans mon exemple. – Stringer

+0

Ensuite, la solution Brians fonctionnera pour vous. Cela ne permettra pas à Foo d'avoir L ([L ([I (42)])]). – nlucaroni

1

Vous ne pouvez pas dire «c'est la liste des membres de certains Foo et d'autres (non Foo) choses » en termes de type F # système. Mais vous pouvez utiliser l'exécution et encore un autre niveau d'indirection:

type Foo = I of int | S of string 

let (|F|L|) (o: obj) = 
    match o with 
    | :? Foo as v -> F v 
    | :? list<Foo> as v -> L v 
    | _ -> failwith "unknown type" 
;; 

let f = function 
    | F _ -> "Foo" 
    | L _ -> "List of Foos" 
;; 

List.map f [ box (I 1); box (S "stuff"); box ([I 2; S "foo"]) ] 
+0

OK, je comprends. Merci!! – Stringer

+2

Vous ne devriez vraiment pas le faire de cette façon: -/ Les tests de type dynamique (:?) Entraînent un gros succès en termes de performance et puisque vous encodez les objets que vous perdez, tapez sécurité - donc vous pouvez atteindre ce 'failwith' cas à l'exécution et ne pas obtenir de soutien du compilateur F #. –