jack-pappas / extcore Goto Github PK
View Code? Open in Web Editor NEWAn extended core library for F#.
License: Apache License 2.0
An extended core library for F#.
License: Apache License 2.0
Analogy as there's non-async pair
type ProtectedStateFunc<'State, 'T, 'Error> = 'State -> Choice<'T * 'State, 'Error>
type StatefulChoiceFunc<'State, 'T, 'Error> = 'State -> Choice<'T, 'Error> * 'State
it would be great to have async one
type AsyncProtectedStateFunc<'State, 'T, 'Error> = 'State -> Async<Choice<'T * 'State, 'Error>>
type AsyncStatefulChoiceFunc<'State, 'T, 'Error> = 'State -> Async<Choice<'T, 'Error> * 'State>> //missing
I think @jack-pappas has not had time for this project for recent months, #32 was closed without merging, this is a very bad sign.
I propose to move this project to fsprojects organization, move to Paket, add a project build script, and release version 1.0 after #32 is merged.
This is a very useful function. I can do something like str |> int.TryParse |> Option.fromBoolAndOut
.
Via the fsharp-opensource
mailing list, Greg Chapman suggested a possible optimization for LazyList
:
I've noticed that both the PowerPack and ExtCore implementations of LazyList wrap a delay around the LazyLists produced by cons and consDelayed. It seems to me that this is unnecessary, since both functions are given the value which will be the head of the new LazyList (so there's no need to delay calculating it). To be specific, here's some code from the PowerPack:
let lzy f = { status = Delayed f } let notlazy v = { status = Value v } let consc x l = CellCons(x,l) let cons x l = lzy(fun () -> (consc x l))
It seems to me that you could change cons to:
let cons x l = notlazy (consc x l)
without breaking anything or decreasing the laziness. Am I missing something?
A number of ExtCore functions, e.g., those in the Seq
module, call GetEnumerator()
on a seq<'T>
but don't dispose the resulting enumerator. This is a problem, because the enumerator can (for example) hold handles to unmanaged resources, which are leaked when the enumerator isn't disposed properly.
The first step to fixing these issues will be to implement a custom IEnumerable<T>
type in ExtCore.Tests; when GetEnumerator()
is called on this type, it should return an instance of IEnumerator<T>
that captures a ref cell stored inside the parent and is incremented when GetEnumerator()
is called and decremented when the enumerator is disposed. This way, unit tests can assert that allocated enumerators have been disposed.
What's worse, it replaces previous redirect with it's own:
before:
<dependentAssembly>
<assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.3.1.0" newVersion="4.3.1.0" />
</dependentAssembly>
after:
<dependentAssembly>
<assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0" />
</dependentAssembly>
For ExtCore v1.0 -- should we support both the Result<_,_>
and Choice<_,_>
type for error-handling, or should we drop Choice<_,_>
and use only Result<_,_>
?
Pros/cons of supporting Result<_,_>
only:
Result<_,_>
is a struct, so doing a blanket replacement throughout code may hurt performance in cases where a Result
is created wrapping a large struct and thereby induces expensive struct copies.Choice<_,_>
breaks backwards-compatibility with code written against current/past versions of ExtCore. Users of the library will have to to make non-trivial changes to their code in order to upgrade to ExtCore v1.0.Pros/cons of supporting Result<_,_>
and Choice<_,_>
:
Result<_,_>
and Choice<_,_>
and use whatever best fits their needs.Result
, once for Choice
). This is transitive as well -- any functions that call these functions also need to be implemented twice, etc.https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/ControlCollections.Choice.fs#L966 and https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/ControlCollections.Choice.fs#L988 should be changed to
checkNonNull "seq" sequence
For ExtCore 1.0, consider replacing the substring
type in favor of the new ReadOnlySpan<char>
type. substring
is useful for avoiding allocations in text-processing code, but unfortunately there are some inconsistencies in it's implementation (and functions in the Substring
module) w.r.t. whether indices used in functions represent an index into the original string or within the substring. Moving to ReadOnlySpan<char>
gives us a chance to fix this, and also provides an API that'll be more compatible with the rest of F# and the broader .NET ecosystem.
["A"; "N"; "N"; "A"] |> List.distinct = []
Issues like #39 and @wallymathieu's work in #31, #32 raise an important question: should ExtCore support/target multiple versions of FSharp.Core?
If not, what should be the policy for determining which version of FSharp.Core we'll target? How would we decide if/when to upgrade the version of FSharp.Core we're referencing?
Another way of looking at this problem: if functionality (types and/or functions) from ExtCore is determined to be useful enough to be merged into FSharp.Core, how do we deal with that in a way which causes the least amount of breakage / code changes for users of ExtCore?
Thoughts? @7sharp9 @vasily-kirichenko @dsyme @TIHan
Such as this:
let inline choiceOfOptionWith e =
Async.map (Choice.ofOptionWith e)
Or something more optimised
I believe the initializer should be called with 'i'
not'count'
like in Array.init here: https://github.com/dotnet/fsharp/blob/ec5bad3a391357e03ff2286a264f0e4faf7d840d/src/fsharp/FSharp.Core/local.fs#L997
see PR:
#50
==
refers to obsolete use ===
===
refers to obsolete use ==
https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/Pervasive.fs#L105-L113
Here is a simple program using TaskBuilder
:
open System.Threading
open System.Threading.Tasks
open ExtCore.Control.Tasks
[<EntryPoint>]
let main _ =
let completed = ref false
let t = tasks {
printfn "Started"
let n = ref 10
let s = ref 0
printfn "Next while"
while 0 < !n do
printfn "Iteration"
s := !n + !s
n := !n - 1
printfn "Sum %A" !s
lock completed <| fun () ->
completed := true
Monitor.PulseAll completed
}
t.Start ()
lock completed <| fun () ->
while not !completed do
Monitor.Wait completed |> ignore
0
Running this program (Mono, but I don't expect different behavior under .Net) I get the following output:
Started
Next while
After which nothing happens. I would expect the computation to run to completion. Like when happens if you replace tasks
with async
and t.Start ()
with Async.Start t
.
Hi there - I just happened to be browsing ExtCore/Pervasives.fs and noticed that Operators.nor is implemented incorrectly (it looks like it must have been copied and pasted from nand): https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/Pervasive.fs#L133
I believe correct implementation would be not (p || q)
There''s ExtCore.Control.Collections.AsyncChoice.Array.fold
for example:
https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/ControlCollections.AsyncChoice.fs#L50
But it does not exists in the NuGet package:
The result of PR #50 has lead to the main branch being now in an error state, see https://travis-ci.org/jack-pappas/ExtCore.
The log appears to be erased, so I cannot see why Travis-CI is in error state. Not sure how to re-run CI:
It'd be good to update the ExtCore.Tests project to use NUnit 3.x (it's currently using the last stable 2.x version). However, this isn't as simple as changing the reference because of the use of the [<ExpectedException>]
attribute which was removed from NUnit 3.x.
There is a way to bring this attribute back for NUnit 3.x:
https://github.com/nunit/nunit-csharp-samples/blob/master/ExpectedExceptionExample/ExpectedExceptionAttribute.cs
Let's either implement that attribute in ExtCore.Tests, or modify the tests to use e.g., Assert.Throws<T>(...)
instead.
It would be useful if ExtCore had online documentation available somewhere (on github pages?). If it is already available, it would be nice if it was linked in the readme; I couldn't find such a link there, and google-fu also failed me. As of now, I unfortunately can't easily learn what exactly is available in ExtCore.
So if you open System
then you get both the one from FSharp.Core and ExtCore so you have to prefix pattern matching on the Error case to avoid collision:
let result =
try Ok (analyse exp basicEnv)
with ex -> Result.Error (ex.Message)
if printResult then
printfn "%s" name
printfn "Expression: %s" (HMBasic.exp.toString exp)
match result with
| Ok result ->
printfn "inferred: %s\n" (HMBasic.ty.toString result)
| Result.Error error -> printfn "inferred: %s\n" error )
I mean its easy enough to prefix, but its unnecessary noise, maybe depreciate the result type or not open is by default.
It seems FX_ATLEAST_FSHARP_3_0
is not actually defined here https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/Control.fs#L790-L795
Greg Chapman submitted this bug report to me a while back via the NuGet gallery. I'm opening an issue here to keep track of it:
Using VSExpress Web 2012, I manually created a WinForms app and used Nuget to add ExtCore to it. I then used the dprintfn function in several places. Although I compiled and ran my app in Debug mode, none of the dprintfn messages appeared in the Debug Output. When I just copied the dprintfn code into my app and used that (rather than the ExtCore version), the debug messages did appear.
I'm guessing that the NuGet ExtCore is a release build. so the Debug.WriteLines get stripped out.
ExtCore has some features requiring the library to be built using the F# proto-compiler (fsc-proto
), most notably the 'tagged' collections types (such as TagMap
) and their supporting modules. I've found these collections to be extremely useful in practice, so I don't want to get rid of them entirely; the requirement of using fsc-proto
to build ExtCore is painful though, and makes maintenance much more difficult.
I was thinking of ways to more-easily use fsc-proto
in CI builds (e.g. with a docker image), but upon reflection I think the most straightforward way forward will be to move the tagged collections into a separate project/assembly (e.g. ExtCore.TaggedCollections) which references ExtCore proper. That won't eliminate the fsc-proto
requirement, but it does allow ExtCore to be updated separately -- we can work out a better solution (maybe) for building the ExtCore.TaggedCollections project later.
in asyncChoice computation IDisposable.Dispose called after first bind instead of calling on computation finish
open System
let mutable disposed = false
[<SetUp>]
let setup() = disposed <- false
[<TearDown>]
let teardown() =
printfn "Should be disposed. Checking..."
Assert.IsTrue(disposed)
type Disposable() =
interface IDisposable with
member x.Dispose() =
printfn "disposing!"
disposed <- true
let createAsyncChoiceDisposable() = async { return Choice1Of2(new Disposable()) }
let waitAsyncChoice() =
asyncChoice {
printfn "waiting"
}
let shouldNotBeDisposed() =
printfn "Should not be disposed. Checking..."
Assert.IsFalse(disposed)
// asyncChoice wrong behavior
[<Test>]
let usingAsyncChoice() : unit =
asyncChoice {
use! d = createAsyncChoiceDisposable()
shouldNotBeDisposed()
let! a = waitAsyncChoice()
shouldNotBeDisposed()
}
|> Async.RunSynchronously
|> Choice.get
|> ignore
// async - expected behavior
let createAsyncDisposable() = async { return (new Disposable()) }
let waitAsync() =
async {
printfn "waiting"
}
[<Test>]
let usingAsync() : unit =
async {
use! d = createAsyncDisposable()
shouldNotBeDisposed()
do! waitAsync()
shouldNotBeDisposed()
}
|> Async.RunSynchronously
|> ignore
I think this problem in TryFinally implementation because target disposed after first bind in case of using try/finally explicit
Hi, after reading (and rereading a few times) xml doc for ExtCore.Control.Collections.Async.Seq.Parallel.batch I expect:
[1..10]
|> Seq.map (fun x -> async { return x * x })
|> ExtCore.Control.Collections.Async.Seq.Parallel.batch 3
expect to return [1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
but it returns [1; 4; 9; 4; 9; 16; 9; 16; 25; 16; 25; 36; 25; 36; 49; 36; 49; 64; 49; 64; 81; 64; 81; 100]
Why batch use Seq.windowed?
I expect that implementation (w/out parameters checking):
let mybatch size (sequence : seq<Async<'T>>) : seq<'T> =
sequence
|> Seq.split size
|> Seq.collect (Async.Parallel >> Async.RunSynchronously)
where Seq.split (maybe not best implementation):
module Seq =
/// Split seq to chunks with size chunkSize (or lesser)
let split chunkSize (s: #seq<_>) =
seq {
let r = ResizeArray<_>()
for x in s do
r.Add(x)
if r.Count = chunkSize then
yield r.ToArray() |> Array.toList
r.Clear()
if r.Count <> 0 then yield r.ToArray() |> Array.toList }
By the way, why there is not Seq.split (maybe better name it 'partition'?) in ExtCore. It is very useful function.
Could perhaps be due to nunit/nunit#2518
It'd make releasing new versions of ExtCore significantly easier if we could build + release new versions of the nuget package directly from within the CI builds. Some initial thoughts:
travis encrypt
to encrypt the nuget API key needed to publish new versions of the package -- for obvious reasons the key should not be made public.
[ci package]
in the commit message. Travis CI does something like this now -- including [ci skip]
in the commit message prevents a commit from triggering a CI build.AsyncProtectedState is not as convenient in case where the state is read only (context).
Any reason these operations dont return dict, while the non-Safe do?
https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/Collections.Dict.fs#L331-L337
Why not:
let updateOrAdd key value (dict : dict<'Key, 'T>) =
// Preconditions
checkNonNull "dict" dict
if dict.IsReadOnly then
invalidOp "Cannot update or add an entry to a read-only dictionary."
lock dict <| fun () ->
dict.[key] <- value
dict
Once the Maintainability tasks project is completed, I think we ought to release the new versions of ExtCore as v1.0.0. The reason for the version bump is that the library has been (more or less) API-stable for a long time, but we will need to make a few breaking changes at some point to be able to properly support new versions of F# without having conflicts between ExtCore
and newer versions of FSharp.Core
.
Current list of breaking changes that'll need to be made:
TaskBuilder
type, which was never properly implemented.==
operator from Pervasives.fs.Result
active pattern from Pervasives.fs -- it conflicts with the new Result<_,_>
type in FSharp.Core.typehandleof<'T>
) in Pervasives.fs which use inline IL and therefore require fsc-proto
to build ExtCore.Choice<_,_>
and Result<_,_>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.