SlideShare a Scribd company logo
yield and return
∼ Poor English ver. ∼
bleis-tift
July 27, 2014
Self introduction
https://twitter.com/bleis
https://github.com/bleis-tift
Yuru-Fuwa F#er in Nagoya
I like static typed functional languages
Agenda
Part1: Computation Expression
Part2:Dierence of yield and return
∼considerations∼
Part3:Dierence of yield and return
∼implementations∼
Part4:Conclusion
I will talk about how to implement computation
expression.
Part1: Computation Expression
Computation expression is...
expression that extends normal F# grammer and
provides some customize points
able to dene an user dene process
.
the grammer of F#
..
.
let someFunc a b =
let x = f a
let y = g b
x + y
.
computation expression
..
.
let someFunc a b = builder {
let! x = f a
let! y = g b
return x + y
}
Usages
Remove nests of match expressions for option
Hide parameters for state
Remove nests of function call for async proc
and so on...
But I will skip these topics today.
The way of implementation
The computation exprs are implemented by
some translation rules in F#
Needless any interfaces
Most important thing is which translated exprs are
compilable
.
.
grammer of computation expr
translate
normal grammer
Let's look at some translation rules together!
Notation
Sans-Serif Code of F#. ex) fun x - x
Serif meta Variables. ex) cexpr
Itaric The part related to the translation. ex)
T(e, C)
Translation rule (most outside)
.
. builder-expr { cexpr }
F#compiler translates following:
.
. let b = builder-expr in {| cexpr |}
b is a fresh variable.
builder-expr
Just a normal expression
Builder is evaluated only once
Dene methods called at runtime into builder
type
All methods are dened as instance method
{| ... |}
Translate expr to core language grammer
ex) {| cexpr |} ... translate cexpr
See below for further detais
cexpr
The most outer target of translation
Other computation expr is represented by ce
cexpr is translated by Delay-trans, Quote-trans,
Run-trans if necessary
Representation of the translation rules
The translation rules are described by T-notation
.
T-notation
..
.T(e, C)
e:The computation expr that will be translated
C:The context that was translated
Find the translation rule that match e, and translate
it
T-notation of {| cexpr |}
.
T-notation
..
. {| cexpr |} ≡ T(cexpr, λv.v)
λv.v is anonymous function
before dot: the parameter
after dot: the function body
v is the translated expression
Function application is done at compile-time
(not run-time)
Trans rule for return
.
Trans rule
..
. T(return e, C) = C(b.Return(e))
if cexpr is return 42 then:
.
Example
..
.
T(return 42, λv.v)
−→(λv.v)(b.Return(42))
−→b.Return(42)
Complete!
Trans rule for let
.
Trans rules
..
.
T(return e, C) = C(b.Return(e))
T(let p = e in ce, C) = T(ce, λv.C(let p = e in v))
.
Example
..
.
T(let x = 42 in return x, λv1.v1)
−→T(return x, λv2.(λv1.v1)(let x = 42 in v2))
−→(λv2.(λv1.v1)(let x = 42 in v2))(b.Return(x))
−→(λv1.v1)(let x = 42 in b.Return(x))
−→let x = 42 in b.Return(x)
Trans rule of if
.
Trans rules
..
.
{| cexpr |} ≡ T(cexpr, λv.v)
T(return e, C) = C(b.Return(e))
T(if e then ce1 else ce2, C) = C(if e then {| ce1 |} else {| ce2 |})
T(if e then ce, C) = C(if e then {| ce |} else b.Zero())
.
Example
..
.
T(if c then return 42, λv1.v1)
−→(λv1.v1)(if c then {| return 42 |} else b.Zero())
−→(λv1.v1)(if c then T(return 42, λv2.v2) else b.Zero())
−→(λv1.v1)(if c then (λv2.v2)(b.Return(42)) else b.Zero())
−→(λv1.v1)(if c then b.Return(42) else b.Zero())
−→if c then b.Return(42) else b.Zero()
Trans rule of ce1; ce2
.
Trans rules
..
.
{| cexpr |} ≡ T(cexpr, λv.v)
T(return e, C) = C(b.Return(e))
T(ce1; ce2, C) = C(b.Combine({| ce1 |},b.Delay(fun () - {| ce2 |})))
.
Example
..
.
T(return 10; return 20, λv1.v1)
−→(λv1.v1)(b.Combine({| return 10 |},b.Delay(fun () - {| return 20 |})))
−→(λv1.v1)
(b.Combine(T(return 10, λv2.v2),b.Delay(fun () - T(return 20, λv3.v3))))
−→(λv1.v1)
(b.Combine((λv2.v2)(b.Return(10)),b.Delay(fun () - (λv3.v3)(b.Return(20)))))
−→(λv1.v1)(b.Combine(b.Return(10),b.Delay(fun () - b.Return(20))))
−→b.Combine(b.Return(10),b.Delay(fun () - b.Return(20)))
Trans rule of while.
Trans rules
..
.
{| cexpr |} ≡ T(cexpr, λv.v)
T(return e, C) = C(b.Return(e))
T(if e then ce, C) = C(if e then {| ce |} else b.Zero())
T(ce1; ce2, C) = C(b.Combine({| ce1 |},b.Delay(fun () - {| ce2 |})))
T(while e do ce, C) = T(ce, λv.C(b.While(fun () - e,b.Delay(fun () - v))))
.
Example
..
.
T (while f() do if g() then return 42 done; return 0, λv1.v1)
−→(λv1.v1)(b.Combine({| while f() do if g() then return 42 |},b.Delay(fun () - {| return 0 |})))
−→(λv1.v1)(b.Combine(
T (if g() then return 42, λv2.b.While(fun () - f(),b.Delay(fun () - v2)))
,b.Delay(fun () - b.Return(0))))
−→(λv1.v1)(b.Combine(
(λv2.b.While(fun () - f(),b.Delay(fun () - v2)))(if g() then b.Return(42) else b.Zero())
,b.Delay(fun () - b.Return(0))))
−→(λv1.v1)(b.Combine(
b.While(fun () - f(),b.Delay(fun () - if g() then b.Return(42) else b.Zero()))
,b.Delay(fun () - b.Return(0))))
−→b.Combine(b.While(fun () - f(),b.Delay(fun () - if g() then b.Return(42) else b.Zero()))
,b.Delay(fun () - b.Return(0)))
Feature of computation expr
Computation expr is similar to
do notation (Haskell)
for expression (Scala)
query expression (C#)
Dierence is computation expr has more exibility
than core language.
Computation expr is more powerful and friendly!
Part2:Dierence of yield and return
∼considerations∼
Trans rules of yield and return
.
Trans rules
..
.
T(yield e, C) = C(b.Yield(e))
T(return e, C) = C(b.Return(e))
Dierent point is only method...
Today's main theme:
Why exist the same rules?
Use properly...?
use yield for yield-like and use return for
return-like...?
use yield for collection-like, otherwise uses
return...?
What's the xxx-like!
I want to decide clearly.
Thinking about dierence between yield
and return
Reer the dictionary:
yield produce/provide
return give back
return should not be continue the following
process.
Monad's return? I don't know:)
Dierence between yield and return
.
yield
..
.
list {
yield 1
printfn done
}
.return
..
.
list {
return 1
printfn done
}
Whether or not to print done
The case of C
return
IET
yield return
yield break
query expression
select
I want to realize something like yield return and
yield break.
seq expression
return is not supported
Dicult for yield break like C#
Let's reimplements seq expression by computation
expression!
Part3:Dierence of yield and return
∼implementations∼
Problem
The trans rule is same yield and return...
Plan 1
The focus on return breaks remained process
Need to return value when called return
Throw exception that wraps returning value in
Return method and catch the exception in Run
method
Impl by exception
.
Builder
..
.
type ReturnExn'T(xs: 'T seq) =
inherit System.Exception()
member this.Value = xs
type SeqBuilder'T() =
member this.Yield(x: 'T) = Seq.singleton x
member this.Return(x: 'T) =
raise (ReturnExn(Seq.singleton x))
member this.Combine(xs: 'T seq, cont: unit - 'T seq) =
Seq.append xs (cont ())
member this.Delay(f: unit - 'T seq) = f
member this.Run(f: unit - 'T seq) =
try f () with
| :? ReturnExn'T as e - e.Value
let seq2'T = SeqBuilder'T() // type function
Impl by exception
.
Usage
..
.
 seq2 { yield 1; yield 2 };;
val it : seqint = seq [1; 2]
 seq2 { return 1; return 2 };;
val it : seqint = seq [1]
Yes!
Impl by exception
Scala uses exception for the part of implements
return and break
Looks like easy
But!
Problem
.
Bad Example
..
.
 seq2 { yield 1; return 2; return 3 };;
val it : seqint = seq [2]
In C#:
.
C#
..
.
IEnumerableint F() {
yield return 1;
yield break 2;
yield break 3; }
It returns the sequencce contains 1 and 2.
Rene version
.
Catch ReturnExn in Combine
..
.
type SeqBuilder'T() =
member this.Yield(x: 'T) = Seq.singleton x
member this.Return(x: 'T) =
raise (ReturnExn(Seq.singleton x))
member this.Combine(xs: 'T seq, cont: unit - 'T seq) =
try
Seq.append xs (cont ())
with
| :? ReturnExn'T as e -
raise (ReturnExn(Seq.append xs e.Value))
member this.Delay(f: unit - 'T seq) = f
member this.Run(f: unit - 'T seq) =
try f () with
| :? ReturnExn'T as e - e.Value
let seq2'T = SeqBuilder'T()
Impl by exception
If provide try-with, need to catch ReturnExn
in try-with and reraise it
Eventually, can't implement clearly
Disinclined for use to exception for control ow
Could be realized at least
Plan 2
Continue or not continue
Insert the judgement of whether to call the rest
process
impl by state eld
.
Builder
..
.
type SeqBuilder() =
let mutable isExit = false
member this.Yield(x) = Seq.singleton x
member this.Return(x) =
isExit - true
Seq.singleton x
member this.Combine(xs, cont) =
if isExit then xs else Seq.append xs (cont ())
member this.Delay(f) = f
member this.Run(f) =
let res = f ()
isExit - false
res
let seq2 = SeqBuilder()
impl by state eld
.
Usage
..
.
 seq2 { yield 1; yield 2 };;
val it : seqint = seq [1; 2]
 seq2 { return 1; return 2 };;
val it : seqint = seq [1]
 seq2 { yield 1; return 2; return 3 };;
val it : seqint = seq [1; 2]
Yes!
impl by state eld
simple
looks like easy
But!
Problem
builder instance has state
use the same builder instance at the same time...
.
.
Thread A
seq2 {
yield 1
; // Combine
yield 2 // oops!
} // Run
val it : seqint = seq [1]
seq2.isExit
false
true
false
Thread B
seq2 {
return 10
} // Run
Rene version
.
Builder
..
.
type SeqBuilder() =
(* ... *)
let seq2 () = SeqBuilder()
.
Usage
..
.
 seq2 () { yield 1; yield 2 };;
val it : seqint = seq [1; 2]
 seq2 () { return 1; return 2 };;
val it : seqint = seq [1]
 seq2 () { yield 1; return 2; return 3 };;
val it : seqint = seq [1; 2]
Impl by state eld
Create the builder instance at every time
Can't forbid that the user share the instance
It's troublesome
Does not stand for practical use...
Plan 3
Problem: state sharing
Solution: use the argument
Carry the state by the argument, and unwrap the
state in Run method
The rest process is not called if the state is
Break in Combine method
Impl by state arg
.
Builder
..
.
type FlowControl = Break | Continue
type SeqBuilder() =
member this.Yield(x) = Seq.singleton x, Continue
member this.Return(x) = Seq.singleton x, Break
member this.Combine((xs, st), cont) =
match st with
| Break - xs, Break
| Continue -
let ys, st = cont ()
Seq.append xs ys, st
member this.Delay(f) = f
member this.Run(f) = f () | fst
let seq2 = SeqBuilder()
Impl by state arg
.
Usage
..
.
 seq2 { yield 1; yield 2 };;
val it : seqint = seq [1; 2]
 seq2 { return 1; return 2 };;
val it : seqint = seq [1]
 seq2 { yield 1; return 2; return 3 };;
val it : seqint = seq [1; 2]
Yes!
Impl by state arg
Symmetry of the return and yield became clear
The implementation is very complex
Looks like good.
Comparison
.
Impl by exception
..
.
member this.Yield(x: 'T) = Seq.singleton x
member this.Return(x: 'T) =
raise (ReturnExn(Seq.singleton x))
.
Impl by state eld
..
.
member this.Yield(x) = Seq.singleton x
member this.Return(x) =
isExit - true
Seq.singleton x
.
Impl by state arg
..
.
member this.Yield(x) = Seq.singleton x, Continue
member this.Return(x) = Seq.singleton x, Break
Plan 4
Impl of exception: use the exception to break
the rest process
It is same to discard continuation
yield: call continuation
return: discard continuation
Impl by continuation
.Builder
..
.
type SeqBuilder() =
member this.Yield(x) = fun k - k (Seq.singleton x)
member this.Return(x) = fun _ - Seq.singleton x
member this.Combine(f, cont) =
fun k - f (fun xs - cont () k | Seq.append xs)
member this.Delay(f) = f
member this.Run(f) = f () id
let seq2 = SeqBuilder()
.Usage
..
.
 seq2 { yield 1; yield 2 };;
val it : seqint = seq [1; 2]
 seq2 { return 1; return 2 };;
val it : seqint = seq [1]
 seq2 { yield 1; return 2; return 3 };;
val it : seqint = seq [1; 2]
Impl by continuation
Symmetry of return and yield is clear
Shortest but complex (and not dene the Bind
method)
The state arg version too
Speed Comparison
Write yield at 100,000 times and execute.
builder time
unsupported return 20.5ms
by exception 20.5ms
by state eld 20.7ms
by state arg 21.2ms
by continuation 22.6ms
seq expr 1.18ms
The dierence is less.
But builer is slower than seq expr in the rst place.
Part4 : Conclusion
Summary
The computation expression is powerful
yield and return have the same translation
rule but the meaning is dierent
The seq expression is not supported return →
reimplementation
Implementations:
by exception
by state eld (deprecated)
by state arg
by continuation
Impl status of some libraries
Design about return ex) seq/list/option
Target libraries:
FSharpx
ExtCore
FSharpPlus
Basis.Core
As of July 21, 2014
Impl status of some libraries
.
Benchmark code
..
.
let xs = [30; 10; 15; 21; -1; 50]
builder {
let i = ref 0
while !i  xs.Length do
if xs.[!i] = -1 then
return false
incr i
return true
}
Can compile it
It returns false-like value
Impl status of some libraries
.
Expanded benchmark code
..
.
let b = builder
b.Run(
b.Delay(fun () -
let i = ref 0
b.Combine(
b.While(
(fun () - !i  xs.Length),
b.Delay(fun () -
b.Combine(
(if xs.[!i] = -1 then b.Return(false)
else b.Zero()),
b.Delay(fun () - incr i; b.Zero())))),
b.Delay(fun () - b.Return(true)))))
FSharpx
can't compile...
FSharpx
The type of Combine is bad.
.
Signature of Combine
..
.'a option * ('a - 'b option) - 'b option
.
Expand of error point
..
.
// 'a option * ('a - 'b option) - 'b option
b.Combine(
// bool option
(if xs.[!i] = -1 then b.Return(false) else b.Zero()),
// unit - 'a option
b.Delay(fun () - incr i; b.Zero()))
.
Correct signature
..
.'a option * (unit - 'a option) - 'a option
ExtCore
can't compile...
ExtCore
The impl of Zero is bad.
.
Implementation of Zero
..
.
member inline __.Zero () : unit option =
Some () // TODO : Should this be None?
comment...
FSharpPlus
can't compile.
Not provide While
Better choice
Basis.Core
can compile.
return false-like value.
Impl status of some libraries
No Game!
Rethink about dierence yield and return
Very few libraries implement computation expr
correctly
There is a problem to be solved before yield and
return
Should we give a semantic dierence really?
Should give if you want to take advantage of
computation expr
Should not give if you provide only Bind and
Return (like FSharpPlus)
Rethink about computation expression
Should Yield and Return receive continuation?
Compile-time translation is ecient
Can implement yield and return by now rules
I want to take this exibility
Suggestion of a Policy
The considered separately depending on the library
design
Case 1: provide monad/monad plus
Case 2: provide more general computing
Case 3: use computaion expr other than monad
Provide monad/monad plus
Provide monad
Required: Bind/Return
Optional: ReturnFrom (for convinience)
Optional: Run
Provide another builder that unwrap the value
Provide monad plus
Required: Bind/Return/Zero/Combine
Zero is mzero, Combine is mplus
Required: Delay (depends on trans rule of
Combine)
member this.Delay(f) = f ()
Provide more general computing
Separate the modules by feature
Builder module for providing Bind/Return
Builder module for providing Bind/Return/Comine
Combine is not mplus. Combine + Delay is
mplus.
Inevitably, required Delay/Run
member this.Delay(f) = f
member this.Run(f) = f ()
Optional: Zero
Support if-expr without else-clause
Use computaion expr other than monad
I have no comments:)
If provide Combine, think about yield and return
Use CustomOperation if necessary
Tasks
Report the bug to FSharpx and ExtCore
Create a library that is divided the module by
feature
Verify builder
Edication
Thanks.

More Related Content

PDF
仕事で使うF#
PDF
Introduction to ad-3.4, an automatic differentiation library in Haskell
PPT
Paradigmas de Linguagens de Programacao - Aula #5
PPTX
Programming Homework Help
PPTX
C Assignment Help
PDF
Pointers & References in C++
PPT
Paradigmas de Linguagens de Programacao - Aula #4
PPTX
pointer, virtual function and polymorphism
仕事で使うF#
Introduction to ad-3.4, an automatic differentiation library in Haskell
Paradigmas de Linguagens de Programacao - Aula #5
Programming Homework Help
C Assignment Help
Pointers & References in C++
Paradigmas de Linguagens de Programacao - Aula #4
pointer, virtual function and polymorphism

What's hot (20)

PPT
FP 201 - Unit 6
PPTX
Pointers, virtual function and polymorphism
PPTX
Rust Intro
PPTX
Pointers in C
PPT
C++tutorial
PPT
Pointers+(2)
PPTX
Learning C++ - Pointers in c++ 2
PPTX
Programming Fundamentals
PPTX
Dynamic Memory Allocation in C
PPTX
Software Construction Assignment Help
PPT
FP 201 Unit 2 - Part 3
PDF
Loops_in_Rv1.2b
PPT
Lec 37 - pointers
PPTX
Pointers
PDF
4th_Ed_Ch03.pdf
PDF
Lecturer23 pointersin c.ppt
PPT
Lec 38.39 - pointers
PPTX
Pointers in C
PDF
Think sharp, write swift
PPT
Pointers in C
FP 201 - Unit 6
Pointers, virtual function and polymorphism
Rust Intro
Pointers in C
C++tutorial
Pointers+(2)
Learning C++ - Pointers in c++ 2
Programming Fundamentals
Dynamic Memory Allocation in C
Software Construction Assignment Help
FP 201 Unit 2 - Part 3
Loops_in_Rv1.2b
Lec 37 - pointers
Pointers
4th_Ed_Ch03.pdf
Lecturer23 pointersin c.ppt
Lec 38.39 - pointers
Pointers in C
Think sharp, write swift
Pointers in C
Ad

Viewers also liked (6)

PDF
No more Legacy documents
PDF
CIのその先へ
PDF
関数型言語のすすめ
PDF
Jenkins User Conference 2012 Tokyo 「SIerのJenkins事情」
PPTX
Lumen使ってみたレポ
PDF
Jenkins実践入門のnext step
No more Legacy documents
CIのその先へ
関数型言語のすすめ
Jenkins User Conference 2012 Tokyo 「SIerのJenkins事情」
Lumen使ってみたレポ
Jenkins実践入門のnext step
Ad

Similar to yield and return (poor English ver) (20)

PDF
Monadologie
PDF
Basic R Data Manipulation
PPTX
functions
PDF
Matlab ch1 intro
PDF
Integral Calculus Anti Derivatives reviewer
PDF
Functional Programming in F#
PPTX
Intro to Matlab programming
PDF
High-Performance Haskell
PPTX
Visualizing and solving Complex Integrals.pptx
PPTX
matlab presentation fro engninering students
PDF
Introduction to Functional Programming with Scala
PDF
Laziness, trampolines, monoids and other functional amenities: this is not yo...
PDF
The Functional Programming Triad of Folding, Scanning and Iteration - a first...
DOCX
B61301007 matlab documentation
PDF
cel shading as PDF and Python description
PDF
Monads - Dublin Scala meetup
PDF
Learn a language : LISP
PDF
Integration material
PDF
Integration
PDF
Scala by Luc Duponcheel
Monadologie
Basic R Data Manipulation
functions
Matlab ch1 intro
Integral Calculus Anti Derivatives reviewer
Functional Programming in F#
Intro to Matlab programming
High-Performance Haskell
Visualizing and solving Complex Integrals.pptx
matlab presentation fro engninering students
Introduction to Functional Programming with Scala
Laziness, trampolines, monoids and other functional amenities: this is not yo...
The Functional Programming Triad of Folding, Scanning and Iteration - a first...
B61301007 matlab documentation
cel shading as PDF and Python description
Monads - Dublin Scala meetup
Learn a language : LISP
Integration material
Integration
Scala by Luc Duponcheel

More from bleis tift (20)

PDF
PCさえあればいい。
PDF
F#の基礎(?)
PPTX
解説?FSharp.Quotations.Compiler
PDF
効果の低いテストの話
PDF
テストの自動化を考える前に
PDF
札束でExcelを殴る
PDF
.NET系開発者から見たJava
PDF
SI屋のためのF# ~DSL編~
PDF
F#事例発表
PDF
yieldとreturnの話
PDF
F#の基礎(嘘)
PDF
現実(えくせる)と戦う話
PDF
ラムダでウィザード 滅せよ手続き、とチャーチは言った (※言ってません)
PDF
async/await不要論
PDF
F#によるFunctional Programming入門
PDF
VBAを書きたくない話(Excel-DNAの紹介)
PDF
Better C#の脱却を目指して
PDF
モナドハンズオン前座
PDF
JSX / Haxe / TypeScript
PDF
自分戦略
PCさえあればいい。
F#の基礎(?)
解説?FSharp.Quotations.Compiler
効果の低いテストの話
テストの自動化を考える前に
札束でExcelを殴る
.NET系開発者から見たJava
SI屋のためのF# ~DSL編~
F#事例発表
yieldとreturnの話
F#の基礎(嘘)
現実(えくせる)と戦う話
ラムダでウィザード 滅せよ手続き、とチャーチは言った (※言ってません)
async/await不要論
F#によるFunctional Programming入門
VBAを書きたくない話(Excel-DNAの紹介)
Better C#の脱却を目指して
モナドハンズオン前座
JSX / Haxe / TypeScript
自分戦略

Recently uploaded (20)

PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Empathic Computing: Creating Shared Understanding
PPT
Teaching material agriculture food technology
PDF
Machine learning based COVID-19 study performance prediction
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
cuic standard and advanced reporting.pdf
PPTX
Cloud computing and distributed systems.
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Electronic commerce courselecture one. Pdf
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Approach and Philosophy of On baking technology
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
NewMind AI Weekly Chronicles - August'25 Week I
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Empathic Computing: Creating Shared Understanding
Teaching material agriculture food technology
Machine learning based COVID-19 study performance prediction
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Review of recent advances in non-invasive hemoglobin estimation
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
cuic standard and advanced reporting.pdf
Cloud computing and distributed systems.
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Electronic commerce courselecture one. Pdf
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Programs and apps: productivity, graphics, security and other tools
Approach and Philosophy of On baking technology
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Network Security Unit 5.pdf for BCA BBA.
NewMind AI Weekly Chronicles - August'25 Week I

yield and return (poor English ver)

  • 1. yield and return ∼ Poor English ver. ∼ bleis-tift July 27, 2014
  • 3. Agenda Part1: Computation Expression Part2:Dierence of yield and return ∼considerations∼ Part3:Dierence of yield and return ∼implementations∼ Part4:Conclusion I will talk about how to implement computation expression.
  • 5. Computation expression is... expression that extends normal F# grammer and provides some customize points able to dene an user dene process . the grammer of F# .. . let someFunc a b = let x = f a let y = g b x + y . computation expression .. . let someFunc a b = builder { let! x = f a let! y = g b return x + y }
  • 6. Usages Remove nests of match expressions for option Hide parameters for state Remove nests of function call for async proc and so on... But I will skip these topics today.
  • 7. The way of implementation The computation exprs are implemented by some translation rules in F# Needless any interfaces Most important thing is which translated exprs are compilable . . grammer of computation expr translate normal grammer Let's look at some translation rules together!
  • 8. Notation Sans-Serif Code of F#. ex) fun x - x Serif meta Variables. ex) cexpr Itaric The part related to the translation. ex) T(e, C)
  • 9. Translation rule (most outside) . . builder-expr { cexpr } F#compiler translates following: . . let b = builder-expr in {| cexpr |} b is a fresh variable.
  • 10. builder-expr Just a normal expression Builder is evaluated only once Dene methods called at runtime into builder type All methods are dened as instance method
  • 11. {| ... |} Translate expr to core language grammer ex) {| cexpr |} ... translate cexpr See below for further detais
  • 12. cexpr The most outer target of translation Other computation expr is represented by ce cexpr is translated by Delay-trans, Quote-trans, Run-trans if necessary
  • 13. Representation of the translation rules The translation rules are described by T-notation . T-notation .. .T(e, C) e:The computation expr that will be translated C:The context that was translated Find the translation rule that match e, and translate it
  • 14. T-notation of {| cexpr |} . T-notation .. . {| cexpr |} ≡ T(cexpr, λv.v) λv.v is anonymous function before dot: the parameter after dot: the function body v is the translated expression Function application is done at compile-time (not run-time)
  • 15. Trans rule for return . Trans rule .. . T(return e, C) = C(b.Return(e)) if cexpr is return 42 then: . Example .. . T(return 42, λv.v) −→(λv.v)(b.Return(42)) −→b.Return(42) Complete!
  • 16. Trans rule for let . Trans rules .. . T(return e, C) = C(b.Return(e)) T(let p = e in ce, C) = T(ce, λv.C(let p = e in v)) . Example .. . T(let x = 42 in return x, λv1.v1) −→T(return x, λv2.(λv1.v1)(let x = 42 in v2)) −→(λv2.(λv1.v1)(let x = 42 in v2))(b.Return(x)) −→(λv1.v1)(let x = 42 in b.Return(x)) −→let x = 42 in b.Return(x)
  • 17. Trans rule of if . Trans rules .. . {| cexpr |} ≡ T(cexpr, λv.v) T(return e, C) = C(b.Return(e)) T(if e then ce1 else ce2, C) = C(if e then {| ce1 |} else {| ce2 |}) T(if e then ce, C) = C(if e then {| ce |} else b.Zero()) . Example .. . T(if c then return 42, λv1.v1) −→(λv1.v1)(if c then {| return 42 |} else b.Zero()) −→(λv1.v1)(if c then T(return 42, λv2.v2) else b.Zero()) −→(λv1.v1)(if c then (λv2.v2)(b.Return(42)) else b.Zero()) −→(λv1.v1)(if c then b.Return(42) else b.Zero()) −→if c then b.Return(42) else b.Zero()
  • 18. Trans rule of ce1; ce2 . Trans rules .. . {| cexpr |} ≡ T(cexpr, λv.v) T(return e, C) = C(b.Return(e)) T(ce1; ce2, C) = C(b.Combine({| ce1 |},b.Delay(fun () - {| ce2 |}))) . Example .. . T(return 10; return 20, λv1.v1) −→(λv1.v1)(b.Combine({| return 10 |},b.Delay(fun () - {| return 20 |}))) −→(λv1.v1) (b.Combine(T(return 10, λv2.v2),b.Delay(fun () - T(return 20, λv3.v3)))) −→(λv1.v1) (b.Combine((λv2.v2)(b.Return(10)),b.Delay(fun () - (λv3.v3)(b.Return(20))))) −→(λv1.v1)(b.Combine(b.Return(10),b.Delay(fun () - b.Return(20)))) −→b.Combine(b.Return(10),b.Delay(fun () - b.Return(20)))
  • 19. Trans rule of while. Trans rules .. . {| cexpr |} ≡ T(cexpr, λv.v) T(return e, C) = C(b.Return(e)) T(if e then ce, C) = C(if e then {| ce |} else b.Zero()) T(ce1; ce2, C) = C(b.Combine({| ce1 |},b.Delay(fun () - {| ce2 |}))) T(while e do ce, C) = T(ce, λv.C(b.While(fun () - e,b.Delay(fun () - v)))) . Example .. . T (while f() do if g() then return 42 done; return 0, λv1.v1) −→(λv1.v1)(b.Combine({| while f() do if g() then return 42 |},b.Delay(fun () - {| return 0 |}))) −→(λv1.v1)(b.Combine( T (if g() then return 42, λv2.b.While(fun () - f(),b.Delay(fun () - v2))) ,b.Delay(fun () - b.Return(0)))) −→(λv1.v1)(b.Combine( (λv2.b.While(fun () - f(),b.Delay(fun () - v2)))(if g() then b.Return(42) else b.Zero()) ,b.Delay(fun () - b.Return(0)))) −→(λv1.v1)(b.Combine( b.While(fun () - f(),b.Delay(fun () - if g() then b.Return(42) else b.Zero())) ,b.Delay(fun () - b.Return(0)))) −→b.Combine(b.While(fun () - f(),b.Delay(fun () - if g() then b.Return(42) else b.Zero())) ,b.Delay(fun () - b.Return(0)))
  • 20. Feature of computation expr Computation expr is similar to do notation (Haskell) for expression (Scala) query expression (C#) Dierence is computation expr has more exibility than core language. Computation expr is more powerful and friendly!
  • 21. Part2:Dierence of yield and return ∼considerations∼
  • 22. Trans rules of yield and return . Trans rules .. . T(yield e, C) = C(b.Yield(e)) T(return e, C) = C(b.Return(e)) Dierent point is only method... Today's main theme: Why exist the same rules?
  • 23. Use properly...? use yield for yield-like and use return for return-like...? use yield for collection-like, otherwise uses return...? What's the xxx-like! I want to decide clearly.
  • 24. Thinking about dierence between yield and return Reer the dictionary: yield produce/provide return give back return should not be continue the following process. Monad's return? I don't know:)
  • 25. Dierence between yield and return . yield .. . list { yield 1 printfn done } .return .. . list { return 1 printfn done } Whether or not to print done
  • 26. The case of C return IET yield return yield break query expression select I want to realize something like yield return and yield break.
  • 27. seq expression return is not supported Dicult for yield break like C# Let's reimplements seq expression by computation expression!
  • 28. Part3:Dierence of yield and return ∼implementations∼
  • 29. Problem The trans rule is same yield and return...
  • 30. Plan 1 The focus on return breaks remained process Need to return value when called return Throw exception that wraps returning value in Return method and catch the exception in Run method
  • 31. Impl by exception . Builder .. . type ReturnExn'T(xs: 'T seq) = inherit System.Exception() member this.Value = xs type SeqBuilder'T() = member this.Yield(x: 'T) = Seq.singleton x member this.Return(x: 'T) = raise (ReturnExn(Seq.singleton x)) member this.Combine(xs: 'T seq, cont: unit - 'T seq) = Seq.append xs (cont ()) member this.Delay(f: unit - 'T seq) = f member this.Run(f: unit - 'T seq) = try f () with | :? ReturnExn'T as e - e.Value let seq2'T = SeqBuilder'T() // type function
  • 32. Impl by exception . Usage .. . seq2 { yield 1; yield 2 };; val it : seqint = seq [1; 2] seq2 { return 1; return 2 };; val it : seqint = seq [1] Yes!
  • 33. Impl by exception Scala uses exception for the part of implements return and break Looks like easy But!
  • 34. Problem . Bad Example .. . seq2 { yield 1; return 2; return 3 };; val it : seqint = seq [2] In C#: . C# .. . IEnumerableint F() { yield return 1; yield break 2; yield break 3; } It returns the sequencce contains 1 and 2.
  • 35. Rene version . Catch ReturnExn in Combine .. . type SeqBuilder'T() = member this.Yield(x: 'T) = Seq.singleton x member this.Return(x: 'T) = raise (ReturnExn(Seq.singleton x)) member this.Combine(xs: 'T seq, cont: unit - 'T seq) = try Seq.append xs (cont ()) with | :? ReturnExn'T as e - raise (ReturnExn(Seq.append xs e.Value)) member this.Delay(f: unit - 'T seq) = f member this.Run(f: unit - 'T seq) = try f () with | :? ReturnExn'T as e - e.Value let seq2'T = SeqBuilder'T()
  • 36. Impl by exception If provide try-with, need to catch ReturnExn in try-with and reraise it Eventually, can't implement clearly Disinclined for use to exception for control ow Could be realized at least
  • 37. Plan 2 Continue or not continue Insert the judgement of whether to call the rest process
  • 38. impl by state eld . Builder .. . type SeqBuilder() = let mutable isExit = false member this.Yield(x) = Seq.singleton x member this.Return(x) = isExit - true Seq.singleton x member this.Combine(xs, cont) = if isExit then xs else Seq.append xs (cont ()) member this.Delay(f) = f member this.Run(f) = let res = f () isExit - false res let seq2 = SeqBuilder()
  • 39. impl by state eld . Usage .. . seq2 { yield 1; yield 2 };; val it : seqint = seq [1; 2] seq2 { return 1; return 2 };; val it : seqint = seq [1] seq2 { yield 1; return 2; return 3 };; val it : seqint = seq [1; 2] Yes!
  • 40. impl by state eld simple looks like easy But!
  • 41. Problem builder instance has state use the same builder instance at the same time... . . Thread A seq2 { yield 1 ; // Combine yield 2 // oops! } // Run val it : seqint = seq [1] seq2.isExit false true false Thread B seq2 { return 10 } // Run
  • 42. Rene version . Builder .. . type SeqBuilder() = (* ... *) let seq2 () = SeqBuilder() . Usage .. . seq2 () { yield 1; yield 2 };; val it : seqint = seq [1; 2] seq2 () { return 1; return 2 };; val it : seqint = seq [1] seq2 () { yield 1; return 2; return 3 };; val it : seqint = seq [1; 2]
  • 43. Impl by state eld Create the builder instance at every time Can't forbid that the user share the instance It's troublesome Does not stand for practical use...
  • 44. Plan 3 Problem: state sharing Solution: use the argument Carry the state by the argument, and unwrap the state in Run method The rest process is not called if the state is Break in Combine method
  • 45. Impl by state arg . Builder .. . type FlowControl = Break | Continue type SeqBuilder() = member this.Yield(x) = Seq.singleton x, Continue member this.Return(x) = Seq.singleton x, Break member this.Combine((xs, st), cont) = match st with | Break - xs, Break | Continue - let ys, st = cont () Seq.append xs ys, st member this.Delay(f) = f member this.Run(f) = f () | fst let seq2 = SeqBuilder()
  • 46. Impl by state arg . Usage .. . seq2 { yield 1; yield 2 };; val it : seqint = seq [1; 2] seq2 { return 1; return 2 };; val it : seqint = seq [1] seq2 { yield 1; return 2; return 3 };; val it : seqint = seq [1; 2] Yes!
  • 47. Impl by state arg Symmetry of the return and yield became clear The implementation is very complex Looks like good.
  • 48. Comparison . Impl by exception .. . member this.Yield(x: 'T) = Seq.singleton x member this.Return(x: 'T) = raise (ReturnExn(Seq.singleton x)) . Impl by state eld .. . member this.Yield(x) = Seq.singleton x member this.Return(x) = isExit - true Seq.singleton x . Impl by state arg .. . member this.Yield(x) = Seq.singleton x, Continue member this.Return(x) = Seq.singleton x, Break
  • 49. Plan 4 Impl of exception: use the exception to break the rest process It is same to discard continuation yield: call continuation return: discard continuation
  • 50. Impl by continuation .Builder .. . type SeqBuilder() = member this.Yield(x) = fun k - k (Seq.singleton x) member this.Return(x) = fun _ - Seq.singleton x member this.Combine(f, cont) = fun k - f (fun xs - cont () k | Seq.append xs) member this.Delay(f) = f member this.Run(f) = f () id let seq2 = SeqBuilder() .Usage .. . seq2 { yield 1; yield 2 };; val it : seqint = seq [1; 2] seq2 { return 1; return 2 };; val it : seqint = seq [1] seq2 { yield 1; return 2; return 3 };; val it : seqint = seq [1; 2]
  • 51. Impl by continuation Symmetry of return and yield is clear Shortest but complex (and not dene the Bind method) The state arg version too
  • 52. Speed Comparison Write yield at 100,000 times and execute. builder time unsupported return 20.5ms by exception 20.5ms by state eld 20.7ms by state arg 21.2ms by continuation 22.6ms seq expr 1.18ms The dierence is less. But builer is slower than seq expr in the rst place.
  • 54. Summary The computation expression is powerful yield and return have the same translation rule but the meaning is dierent The seq expression is not supported return → reimplementation Implementations: by exception by state eld (deprecated) by state arg by continuation
  • 55. Impl status of some libraries Design about return ex) seq/list/option Target libraries: FSharpx ExtCore FSharpPlus Basis.Core As of July 21, 2014
  • 56. Impl status of some libraries . Benchmark code .. . let xs = [30; 10; 15; 21; -1; 50] builder { let i = ref 0 while !i xs.Length do if xs.[!i] = -1 then return false incr i return true } Can compile it It returns false-like value
  • 57. Impl status of some libraries . Expanded benchmark code .. . let b = builder b.Run( b.Delay(fun () - let i = ref 0 b.Combine( b.While( (fun () - !i xs.Length), b.Delay(fun () - b.Combine( (if xs.[!i] = -1 then b.Return(false) else b.Zero()), b.Delay(fun () - incr i; b.Zero())))), b.Delay(fun () - b.Return(true)))))
  • 59. FSharpx The type of Combine is bad. . Signature of Combine .. .'a option * ('a - 'b option) - 'b option . Expand of error point .. . // 'a option * ('a - 'b option) - 'b option b.Combine( // bool option (if xs.[!i] = -1 then b.Return(false) else b.Zero()), // unit - 'a option b.Delay(fun () - incr i; b.Zero())) . Correct signature .. .'a option * (unit - 'a option) - 'a option
  • 61. ExtCore The impl of Zero is bad. . Implementation of Zero .. . member inline __.Zero () : unit option = Some () // TODO : Should this be None? comment...
  • 64. Impl status of some libraries No Game!
  • 65. Rethink about dierence yield and return Very few libraries implement computation expr correctly There is a problem to be solved before yield and return Should we give a semantic dierence really? Should give if you want to take advantage of computation expr Should not give if you provide only Bind and Return (like FSharpPlus)
  • 66. Rethink about computation expression Should Yield and Return receive continuation? Compile-time translation is ecient Can implement yield and return by now rules I want to take this exibility
  • 67. Suggestion of a Policy The considered separately depending on the library design Case 1: provide monad/monad plus Case 2: provide more general computing Case 3: use computaion expr other than monad
  • 68. Provide monad/monad plus Provide monad Required: Bind/Return Optional: ReturnFrom (for convinience) Optional: Run Provide another builder that unwrap the value Provide monad plus Required: Bind/Return/Zero/Combine Zero is mzero, Combine is mplus Required: Delay (depends on trans rule of Combine) member this.Delay(f) = f ()
  • 69. Provide more general computing Separate the modules by feature Builder module for providing Bind/Return Builder module for providing Bind/Return/Comine Combine is not mplus. Combine + Delay is mplus. Inevitably, required Delay/Run member this.Delay(f) = f member this.Run(f) = f () Optional: Zero Support if-expr without else-clause
  • 70. Use computaion expr other than monad I have no comments:) If provide Combine, think about yield and return Use CustomOperation if necessary
  • 71. Tasks Report the bug to FSharpx and ExtCore Create a library that is divided the module by feature Verify builder Edication