2017-10-20 18 views
0

Je veux écrire un exemple de fonction qui prend une liste de n'importe quel type et retourne l'élément head uniquement si la liste est une liste de réels.ML comment vérifier le type de liste et donner une erreur de massage?

Dans le cas contraire, la fonction doit donner le message d'erreur

. . . E r r o r: opérateur et opérande ne sont pas. . .

datatype typeR = Real of real 
fun head(xs) = 
    case xs of 
     [] => raise List.Empty | 
      Real (x::_) => x:real ; 

Répondre

1
(fn x:real list => hd x) [ 4 ,5 ]; 
out> error: Type error in function application 
(fn x:real list => hd x) [ 4.0 ,5.0 ]; 
out> it = 4.0: real 
+4

Veuillez ajouter une explication de votre code. –

+0

'(fn x: liste réelle => hd x)' ne * prend pas une liste de type *, mais seulement une liste de réels. Mais il ne renvoie * l'élément head que si la liste est une liste de réels *, et il produit une erreur de type lorsqu'il n'est pas soumis à une liste de réels. Alternativement, 'hd: real list -> real'. –

2

Ce n'est pas tout à fait clair ce que vous êtes après - vous ne pouvez pas écrire une fonction qui prend « tout type » et examine ensuite le type de paramètre.
(écriture head(xs), sans annotation de type, ne fait pas head une fonction qui prend tout type. Son type est déduit.)

Si vous voulez une fonction typeR list -> real, votre principale erreur a été écrit Real (x::_) où vous devriez avoir écrit (Real x) :: _.
C'est,

fun head(xs) = 
    case xs of 
     [] => raise List.Empty 
    | (Real x)::_ => x 

ou, plus idiomatiques,

fun head [] = raise List.Empty 
    | head (Real x :: _) = x 
0

d'abord quelques commentaires:

  • Cette fonction est sujette à l'échec car elle accepte seulement une marge de son possible contribution. Écrivez les fonctions totales quand vous le pouvez.

  • raise Empty ne serait pas descriptif de la situation où la liste est non vide mais le premier élément ne contient pas de réel. Une autre exception devrait être soulevée alors.

  • La condition suivante est hautement suspecte.

    Dans le cas contraire, la fonction doit donner le message d'erreur

    . . . E r r o r: opérateur et opérande ne sont pas. . .

    Il est suggéré de ne pas faire la différence entre les exceptions d'exécution et les erreurs de compilation. Ceci est symptomatique pour une expérience de programmation avec des langages typés dynamiquement où les erreurs et les exceptions sont toutes traitées après le démarrage du programme.

Puis quelques idées:

Listes dans Standard ML sont homogènes, ce qui signifie qu'ils ne peuvent être d'un type à un moment déterminé dans la phase de vérification de type de compilation. Il y a plusieurs façons de gérer cela et d'obtenir un typage plus dynamique;

  • Using algebraic data types [wiki.haskell.org]:

    datatype dynamic = R of real 
           | I of int 
           | B of bool 
           | S of string 
    fun headR [] = raise Empty 
        | headR (R r :: _) = r 
        | headR _ = raise Domain 
    

    Alors headR n'accepte pas réellement tout type. Il en accepte exactement un, dynamic, qui peut contenir n'importe quelle quantité fixe de constructeurs de valeurs avec des paramètres de type arbitraire. Cela imite les listes hétérogènes:

    val foos = [R 42.0, I 10, B true, S "Hello, World!"] 
    
  • Using exceptions [informallyabstract.blogspot.com]:

    datatype dynamic = Dynamic of exn 
    exception IsReal of real 
    fun wrap_real r = Dynamic (IsReal r) 
    fun unwrap_real (Dynamic ex) = raise ex handle IsReal r => r 
    fun headR (d::_) = unwrap_real 
        | headR [] = raise Empty 
    

    Alors headR aussi accepte que un type, dynamic et échoue à tout exception qui a été utilisé à la place de l'emballage real. La différence entre l'utilisation d'exceptions et une définition datatype régulière est que les exceptions peuvent être étendues avec de nouveaux constructeurs plus tard:

    exception IsString of string 
    fun wrap_string r = Dynamic (IsString r) 
    fun unwrap_string (Dynamic ex) = raise ex handle IsString r => r 
    val foos = [wrap_real 42.0, wrap_string "This didn't exist before."] 
    

Ni sont préférables car ils présentent un risque inutile d'échec de l'exécution.