How to guarantee referential transparency in F # applications?

So, I'm trying to learn FP, and I'm trying to draw attention to link transparency and side effects.

I learned that making all effects explicit in the type system is the only way to guarantee referential transparency:

The idea of ​​"mostly functional programming" is not feasible. It is impossible to make necessary Programming languages ​​are safer, only partially eliminating the implicit side effects. Leaving one kind of effect, often enough to simulate the effect that you just tried to remove. On the other hand, resolving “forgotten” effects in a pure language also creates chaos in its own way.

Unfortunately, there is no middle ground, and we are faced with the classic dichotomy: scourging the middle ground, which is the choice of either (a) attempts to tame effects using annotations of purity, but fully embracing the fact that your code is still significantly efficient; or (b) fully embracing purity, making all effects explicit in the type system and pragmatic - Source

I also found out that unclean FP languages ​​like Scala or F # cannot guarantee referential transparency:

The ability to enforce referential transparency is largely incompatible with Scala's goal of having a Java-compatible class / object system. - Source

And that in non-pure FP, the programmer must provide referential transparency:

, ML, Scala F #, , , , Clojure Scheme, , -

F #, .Net-, :

, F #, F #?

+4
3

, F #. F # , .NET, , , Haskell, , , .


F #, .

, F # , Haskell, "" , .

, , , :

/// A value of type IO<'a> represents an action which, when performed (e.g. by calling the IO.run function), does some I/O which results in a value of type 'a.
type IO<'a> = 
    private 
    |Return of 'a
    |Delay of (unit -> 'a)

/// Pure IO Functions
module IO =   
    /// Runs the IO actions and evaluates the result
    let run io =
        match io with
        |Return a -> a            
        |Delay (a) -> a()

    /// Return a value as an IO action
    let return' x = Return x

    /// Creates an IO action from an effectful computation, this simply takes a side effecting function and brings it into IO
    let fromEffectful f = Delay (f)

    /// Monadic bind for IO action, this is used to combine and sequence IO actions
    let bind x f =
        match x with
        |Return a -> f a
        |Delay (g) -> Delay (fun _ -> run << f <| g())

return IO.

fromEffectful unit -> 'a IO.

bind - .

run IO . unsafePerformIO Haskell.

.


: F #?

F # Haskell , F # , Haskell . Haskell ( , .NET, ) , , /IO, .

IO Haskell, ( ) - - , - . , .

, F #, :

let randomSeq = Seq.init 4 (fun _ -> rnd.Next())
let sortedSeq = Seq.sort randomSeq

printfn "Sorted: %A" sortedSeq
printfn "Random: %A" randomSeq

, , , .

. , , - . , , .

. , Seq.cache, , , .

, , , , F # Haskell.


, , . Mark Seemann , , - , .

IO , IO, .

, F #, " ". F #, . , IO , .


, , , Curse of the Excluded Middle, , , .

, , , , / , , F # .

, F # , " " - .

+5

, - , , , .

F #, , . - . ( , , , , .)

, "". , , , - .

:

, .

, "" ( , ), , .

, , , .

, - , . , ().

, FP, Scala F #, :

, - " " - , . ( ), " ". - , . .

+5

: " F # . , ".

, , " - " , F #:

  • , while , ref ..
  • ( , , , ..).
  • If you need to do IO at some point, create your program so that they are separate from your purely functional code. Remember that functional programming is about limiting and highlighting side effects.
  • Algebraic data types (ADTs) AKA "discriminated joins" instead of objects.
  • Learning to love laziness.
  • Monad Coverage.
0
source

Source: https://habr.com/ru/post/1651808/


All Articles