2017-02-05 3 views
2

Я пытаюсь изучить F #, и я пытаюсь создать некоторые простые функции как часть этого обучения.Перемещение списка, а затем добавление нового элемента

Я создал функцию, которая добавляет элемент в список, а затем меняет результат. Это работает очень хорошо в интерактивном окне F # в Visual Studio

let addThenReverse n list = 
match list with 
| [] -> [] 
| _ -> n::list |> List.rev 

addThenReverse 0 [1;2;3] //results in [3; 2; 1; 0] 

Но у меня возникают трудности с написанием функции, которая бы полностью изменить список затем добавить элемент к нему.

let reverseThenAdd n list = 
    match list with 
    | [] -> [] 
    | _ -> List.rev list |> n::list 

reverseThenAdd 9 [1;2;3] //desired result [3; 2; 1; 9] 

РЕДАКТИРОВАТЬ Желаемый результат для вышеизложенного должно быть [9; 3; 2; 1]. Хорошо сделано тем, кто это заметил!

Эта вторая функция не компилируется, и я получаю предупреждение «Это выражение, как ожидается, иметь тип» список -> «список б, но здесь имеет тип„списка с“

Любые варианты я стараюсь, кажется, результат другие ошибки компиляции. Я предполагаю (но не знаю, как), что мне нужно использовать новый список, созданный в результате «List.rev list», возможно, назначив его переменной.

+3

Несомненно, результат 'addThenReverse 0 []' должен быть '[0]'? –

+0

@RobLyndon Я отправился с более грандиозными планами, чем просто поворот списка и добавление нового предмета, но поскольку это становилось все труднее, мне пришлось обуздать энтузиазм и снизить мои взгляды. Вот почему логика с пустым списком выглядит немного странно. Большое спасибо за ваш ответ и комментарий! –

ответ

4

Проблема в том, что вы передаете обратный список в выражение конкатенации и отбрасываете компилятор. Вы должны сделать:

let reverseThenAdd n list = 
    match list with 
    | [] -> [] 
    | _ -> n :: (List.rev list) 

reverseThenAdd 9 [1;2;3] //desired result [3;2;1;9] 

, что означает, что вы добавляете n в список в результате (List.rev list)

+0

Мне нравится этот ответ, так как это облегчает понимание моего «C#» условного мозга. Скобки говорят, что сначала сделайте этот бит, а затем добавьте в перевернутый список. Я отметил это как мой принятый ответ, так как он напрямую отвечает на мой вопрос. –

4

Я немного смущен вашими желаемыми результатами. У Luiso есть версия вашего кода, которая исправит компилятор, но он не будет соответствовать вашему желаемому результату. С

let reverseThenAdd n list = 
    match list with 
    | [] -> [] 
    | _ -> n :: (List.rev list) 

reverseThenAdd 9 [1;2;3] //desired result [3; 2; 1; 9] 

фактическим результатом будет [9; 3; 2; 1]. Если комментарий - опечатка, и это на самом деле ваш желаемый результат, то ответ Луисо работает. В противном случае нет существенной разницы между addThenReverse и reverseThenAdd, потому что «добавить» означает что-то другое (добавление и добавление) в каждом случае.

Обратите внимание, что я думаю, что в обоих случаях первый случай должен быть

| [] -> [n] 

вместо

| [] -> [] 

На самом деле, я не думаю, что вам нужно заявление матч на всех. Я думаю, что математически корректная формулировка будет:

let addThenReverse n list = n::list |> List.rev 
let reverseThenAdd n list = n::(list |> List.rev) 

Тогда вы бы

addThenReverse 0 [] // result: [0] 
reverseThenAdd 0 [] // result: [0] 
addThenReverse 9 [1; 2; 3] // result: [3; 2; 1; 9] 
reverseThenAdd 9 [1; 2; 3] // result: [9; 3; 2; 1] 

ДОБАВЛЕНИЕ

Я фанат экспрессивного кода. Такой элегантный, как F #, все же можно написать код, который скрывает то, что вы на самом деле пытаетесь сделать.Код выше работ, но вы можете сделать его более выразительным, и узнать немного больше о том, как язык работы с, используя оператор композиции:

let add n list = n::list 
let reverse = List.rev 
let addThenReverse n = add n >> reverse 
let reverseThenAdd n = reverse >> add n 

Это дает те же результаты, как и раньше, но он выражает то, что вы «делайте более ясно. Верный духу функционального программирования, вы говорите компилятору , что делать, а не как, чтобы сделать это.

+1

Привет, Роб, Спасибо за этот комментарий и его полезные указатели. Я был действительно разорван между принятием вашего ответа и Луисо. Я принял Луисо, только на том основании, что он прямо ответил на мой вопрос. Я хотел бы принять оба, так как ваш ответ указывает мне на большее обучение в F #. Я проголосовал за ваш ответ и Луисо. –

+1

Не стоит беспокоиться о Даниэле. Рад, что смог помочь. –

Смежные вопросы