2009-07-22 6 views
0

Je voudrais commencer quelques questions sur la simplification des différentes expressions en F #. Tout le monde a des idées pour une implémentation meilleure et/ou plus simple de insertAt (les paramètres peuvent aussi être réordonnés). Des listes ou des séquences pourraient être utilisées.insertAt en F # plus simple et/ou mieux

Voici une implémentation de départ:

let insertAt x xs n = Seq.concat [Seq.take n xs; seq [x]; Seq.skip n xs] 
+0

Il y a un certain nombre de bonnes réponses à cette question déjà, mais je voulais mettre en garde que je pense que cette fonction est probablement rarement utile; La plupart du temps vous pouvez utiliser insertAt peut être dans un algorithme/implémentation mieux servis par mutables et System.Collections.Generic.List, ou une structure de données de valeur-clé. – Brian

Répondre

2

Le dannyasher de mise en œuvre affichée est un non tail-recursive un. Afin de rendre la fonction plus efficace, nous devons introduire un paramètre d'accumulateur explicite qui rend la fonction récursive et permet au compilateur d'optimiser les frais généraux de récursion loin:

let insertAt = 
    let rec insertAtRec acc n e list = 
     match n, list with 
     | 0, _  -> (List.rev acc) @ [e] @ list 
     | _, x::xs -> insertAtRec (x::acc) (n - 1) e xs 
     | _  -> failwith "Index out of range" 

    insertAtRec [] 
+0

La correspondance de modèle rend le code plus compliqué dans ce cas . Je recherche une implémentation plus courte et plus simple. –

+0

Vous avez également demandé de meilleures solutions ... La vôtre est extrêmement simple. – Dario

0

De Haskell Wiki - http://www.haskell.org/haskellwiki/99_questions/21_to_28

insertAt :: a -> [a] -> Int -> [a] 
insertAt x ys  1 = x:ys 
insertAt x (y:ys) n = y:insertAt x ys (n-1) 

Je ne suis pas un F # programmeur donc je ne connais pas la syntaxe équivalente pour F #, mais cela est une belle définition récursive pour insertAt

+0

Oui, j'ai eu le quiz à partir de là. Mais j'essaie de l'implémenter en F # pour m'entraîner. Donc, je voudrais trouver une implémentation plus simple que la mienne exactement en F #. Le plus simple que j'ai eu dans Haskell était: insertAt x xs n = prendre n xs ++ [x] ++ drop n xs Mais ce n'est pas si optimal. Peut être une réponse Haskell simple et optimale sera: insertAt x xs n = let (avant, après) = splitAt n xs avant ++ [x] ++ après –

1

Voici une implémentation F # de l'insertion de la liste Haskell:

let rec insertAt x ys n = 
    match n, ys with 
    | 1, _  
    | _, []  -> x::ys 
    | _, y::ys -> y::insertAt x ys (n-1) 

let a = [1 .. 5] 
let b = insertAt 0 a 3 
let c = insertAt 0 [] 3 

> 
val a : int list = [1; 2; 3; 4; 5] 
val b : int list = [1; 2; 0; 3; 4; 5] 
val c : int list = [0] 

Mon Haskell n'est pas assez bon pour savoir si le cas de passer une liste vide est correctement pris en charge dans la fonction Haskell. En F #, nous prenons explicitement en compte la liste vide dans le second cas de match.

Danny

1

Pour le cas où vous voulez vraiment travailler avec la séquence:

let insertAt x ys n = 
    let i = ref n 
    seq { 
    for y in ys do 
    decr i 
    if !i = 0 then yield x 
    yield y 
    } 

Pour tous les autres cas, la réponse de dannyasher est définitivement plus agréable et plus rapide.

2

SEQS utilisant récursive:

let rec insertAt = function 
    | 0, x, xs -> seq { yield x; yield! xs } 
    | n, x, xs -> seq { yield Seq.hd xs; yield! insertAt (n-1, x, Seq.skip 1 xs) } 
+0

J'aime cette solution! Mais je n'aime pas qu'on utilise des tuples au lieu d'arguments séparés. Avec les tuples, il est plus difficile d'utiliser une application partielle des paramètres. –