Как сделать изменяемый аргумент в функции через F #? - PullRequest
0 голосов
/ 07 сентября 2018

Извините за мой вопрос, но я не понял ответов, связанных с этим вопросом, поэтому я надеюсь, что кто-то сможет просветить меня.

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

Я получаю следующую ошибку:

"This value is not mutable. Consider using the mutable keyword let mutable n = expression"

Мой код выглядит так:

let loop5( n ) =  

    let mutable x = 0

    while n > 0 do

        x <- x + 1
        n <- n + 1

    printfn "loop5(): x=%i for n=%i" x n 

loop5(4)

Я пытаюсь написать функцию, похожую на эту (псевдокод):

loop5(n)

    x = 0

    while n > 0

         x = x + 1
         n = n + 1

    return x

Надеюсь, я сформулировал четкий вопрос, и кто-то может помочь мне здесь :-) Хороших выходных

Ответы [ 2 ]

0 голосов
/ 07 сентября 2018

Вы пытаетесь изменить параметр цикла n. Параметр не является изменяемым, поэтому компилятор не позволяет вам. Это именно то, что говорит вам ошибка.

Теперь, чтобы ошибка исчезла, вы должны сделать переменную непостоянной. Однако вы не можете сделать параметр функции изменяемым, так что это не вариант.

Здесь вы хотите подумать, каким должен быть смысл вашей программы. Должна ли функция loop передавать обновленное значение n обратно вызывающей стороне, или вся мутация - это ее внутреннее дело? Если это первое, см. Ответ @ AnyMoose, но из вашего примера и объяснения, я подозреваю, что это второе. Если это так, просто сделайте изменяемую копию параметра и работайте с ним:

let loop n' =
    let mutable x = 0
    let mutable n = n'

    ...

Отдельно, я хочу отметить, что ваша программа, как написано, будет фактически зацикливаться бесконечно (или до тех пор, пока не обернется вокруг значения max int), потому что вместо уменьшения n на каждом шаге вы увеличиваете его. Если вы хотите, чтобы ваша программа действительно заканчивалась до следующего Ледникового периода, вам нужно уменьшать n с каждой итерацией:

n <- n - 1
0 голосов
/ 07 сентября 2018

Ref ячейки

Ref клетки обходят некоторые ограничения изменчивости. Фактически, ref-ячейки - это очень простые типы данных, которые оборачивают изменяемое поле в тип записи. Ссылочные ячейки определяются F # следующим образом:

type 'a ref = { mutable contents : 'a }

Библиотека F # содержит несколько встроенных функций и операторов для работы с ячейками ref:

let ref v = { contents = v }      (* val ref  : 'a -> 'a ref *)
let (!) r = r.contents            (* val (!)  : 'a ref -> 'a *)
let (:=) r v = r.contents <- v    (* val (:=) : 'a ref -> 'a -> unit *)

Функция ref используется для создания ячейки ref,! Оператор используется для чтения содержимого ячейки ref, а оператор: = используется для назначения ячейке ref нового значения. Вот пример в ФСИ:

let x = ref "hello";;

val x : string ref

x;; (* returns ref instance *)
val it : string ref = {contents = "hello";}

!x;; (* returns x.contents *)
val it : string = "hello"

x := "world";; (* updates x.contents with a new value *)
val it : unit = ()

!x;; (* returns x.contents *)
val it : string = "world"

Поскольку ячейки ref размещаются в куче, они могут совместно использоваться несколькими функциями:

open System

let withSideEffects x =
    x := "assigned from withSideEffects function"

let refTest() =
    let msg = ref "hello"
    printfn "%s" !msg

    let setMsg() =
        msg := "world"

    setMsg()
    printfn "%s" !msg

    withSideEffects msg
    printfn "%s" !msg

let main() =
    refTest()
    Console.ReadKey(true) |> ignore

main()

Функция withSideEffects имеет тип val withSideEffects: строка ref -> unit. Эта программа выводит следующее:

привет мир

Назначено из функции withSideEffects

Функция withSideEffects названа таковой, поскольку она имеет побочный эффект, то есть может изменять состояние переменной в других функциях. Клетки Ref должны рассматриваться как огонь. Используйте его осторожно, когда это абсолютно необходимо, но избегайте его в целом. Если вы обнаружите, что используете Ref Cells при переводе кода с C / C ++, то некоторое время игнорируйте эффективность и посмотрите, сможете ли вы обойтись без Ref Cells или, в худшем случае, используя mutable. Вы часто сталкивались с более элегантным и более подходящим алгоритмом

Aliasing Ref Cells

Примечание. Несмотря на то, что в императивном программировании широко используются псевдонимы, у этой практики есть ряд проблем. В частности, это затрудняет отслеживание программ, поскольку состояние любой переменной может быть изменено в любой точке приложения. Кроме того, многопоточные приложения, совместно использующие изменяемое состояние, трудно рассуждать, так как один поток может потенциально изменить состояние переменной в другом потоке, что может привести к ряду незначительных ошибок, связанных с состояниями гонки и мертвыми блокировками. Ячейка ref очень похожа на указатель C или C ++. Можно указывать две или более ячейки ссылки на один и тот же адрес памяти; изменения в этом адресе памяти изменят состояние всех ссылочных ячеек, указывающих на него. Концептуально этот процесс выглядит следующим образом:

Допустим, у нас есть 3 ячейки ссылки, смотрящие на один и тот же адрес в памяти:

Три ссылки на целое число со значением 7

cell1, cell2 и cell3 все указывают на один и тот же адрес в памяти. Свойство .contents каждой ячейки равно 7. Допустим, в какой-то момент в нашей программе мы выполняем код cell1: = 10, это меняет значение в памяти на следующее:

Три ссылки на целое число со значением 10

При назначении cell1.contents нового значения, переменные cell2 и cell3 также были изменены. Это можно продемонстрировать с помощью fsi следующим образом:

let cell1 = ref 7;;
val cell1 : int ref

let cell2 = cell1;;
val cell2 : int ref

let cell3 = cell2;;
val cell3 : int ref

!cell1;;
val it : int = 7

!cell2;;
val it : int = 7

!cell3;;
val it : int = 7

cell1 := 10;;
val it : unit = ()

!cell1;;
val it : int = 10

!cell2;;
val it : int = 10

!cell3;;
val it : int = 10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...