Git Product home page Git Product logo

fscontrol's People

Contributors

atifaziz avatar cloudroutine avatar cmdq avatar gdennie avatar gusty avatar mausch avatar otf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fscontrol's Issues

Delay, Combine.

It would be nice to allow other applications to create generic workflows. Currently a simple monad workflow is possible but in F# there are more operations available, some of them depends on the type, like Delay and Combine. So it worths exploring the possibility of adding Delay, Combine as method-classes and see what comes up.
There is some potential inspiration here.

Show typeclass?

I think it could be useful to have a Show typeclass to escape the fact that everything has a ToString() even when it doesn't make sense. And even worse, it's culture-dependent unless you pass CultureInfo.InvariantCulture, which makes a lot of code referentially opaque.

What do you think?

Shadowing as a workaround for orphans

I've been thinking about a workaround for orphan instances. One way would be to shadow the original inline function and add another dictionary/lookup type.

For example, say you want to use Fleece to serialize a System.Collections.Generic.HashSet<T>. This type is currently not defined in the ToJSON class in Fleece, so it would be an orphan. Here's the shadowing:

open System.Collections.Generic
open System.Json
open Fleece
open ReadOnlyCollectionsExtensions

type MyJSON = MyJSON with
    static member inline ToJSON (x: _ HashSet) =
        JArray ((Seq.map toJSON x).ToReadOnlyList())

let inline iToJSON (a: ^a, b: ^b, z: ^z) =
    ((^a or ^b or ^z) : (static member ToJSON: ^z -> JsonValue) z)
let inline toJSON x = iToJSON (ToJSONClass, MyJSON, x)

(* original definitions:
let inline iToJSON (a: ^a, z: ^z) =
    ((^a or ^z) : (static member ToJSON: ^z -> JsonValue) z)
let inline toJSON (x: 'a) : JsonValue = iToJSON (ToJSONClass, x)
*)

let set1 = HashSet [1;2;3]
let setJSON = toJSON set1
let stringJSON = toJSON "abc" // instances defined in ToJSONClass still work
printfn "%s" (setJSON.ToString())

I'm almost certain this can also be done with the FsControl convention, but surely you can figure out how faster than me :)
The obvious downsides:

  • You have to look up the original definition of the function you want to shadow.
  • You have to redefine any other functions that depend on the function you're shadowing (annoying, but otherwise things would break horribly)

Do you see any other downsides? What do you think?

Numeric code needs redesign.

The Numeric file needs to be 'dehaskellyfied' (or at least de-haskell98-fied).
It is almost a 100% copy from the old typeclasses project which tried to emulate Haskell.
Redesign should aim to:

  • F# Generic Math.
  • Get closer to the F# core standards: GenericZero, Abs, Sign ...
  • Reduce number of types defined, for instance Ratio. That's not the goal of FsControl, it should be in an external library.
  • Reduce number of functions defined, like gcd, for the same reason.
  • Compatibility with common Numeric libraries.

Since this is .NET, generic math comes with a cost (strict math operators), so the idea is that external libraries should be able to provide it as an option, by opening a specific Module.

Functions derived from sequenceA get unsolved type constraints.

If we try to define replicateM for Lists:

let inline replicateM n x = sequenceA (List.replicate n x);;

we get:

error FS0001: A type parameter is missing a constraint 'when (FsControl.Traverse or  ^a Microsoft.FSharp.Collections.list or  ^d) : (static member Traverse :  ^a Microsoft.FSharp.Collections.list * ('?63560 -> '?63560) *  ^d * FsControl.Traverse ->  ^d)'

If we try it for Sequences it works fine.

Cannot build tests in Debug mode with either F# 4.0 nor F# 4.1

3>D:\github\FsControl\FsControl.Test\UnitTest.fs(122,40): error FS0193: A type parameter is missing a constraint 'when (FsControl.SequenceA or Microsoft.FSharp.Collections.seq< ^a> or ^d) : (static member SequenceA : Microsoft.FSharp.Collections.seq< ^a> * ^d * FsControl.SequenceA -> ^d)'

Skip and Take throw Exception.

An exception is thrown when outside the bounds but that's a problem when using seq aiming for laziness, it will force you to check first the length of the sequence.
That's how they're implemented in F# but I prefer the Linq implementation which works as Haskell's drop and take, in those cases it returns an empty list which logically represents 'no results'.

Change Namespace.

I named it Abstractions because I didn't want to name TypeClasses, because they are not real type classes.

But I like the term 'type methods' to name this technique, indeed it's a type (ie: Bind) with a single method (instance).

So what about changing the Abstractions namespace to TypeMethods?

Wrong Monoid instance?

The Monoid instance for ('T->'U) is currently defined as function composition.
However in Haskell is defined as a function where 'U is a Monoid, so mappend is:

mappend f g x = f x `mappend` g x

The current definition is in fact the same as the one for Endo which is another reason to consider to change it.

Alternative typeclass/overload convention

In Fleece I started with the usual typeclass pattern used in FsControl, then I switched to a more ad-hoc pattern.

I'm not sure if the simplification I was able to make, e.g.

static member instance (ToJSON, x: bool, _:JsonValue) = fun () -> JBool x

to

static member ToJSON (x: bool) = JBool x

came from the ad-hoc inline "instance" or my own misunderstanding of the static type resolution mechanism.

Another benefit of this approach is that Visual Studio is more explicit about the requirements of an inline function. For example hovering over the roundtrip function, VS says "requires member ToJSON and member FromJSON and equality". With the usual approach it would say "requires member instance and member instance and equality".

The downsides I see are:

  1. In the example above, if you mistype "ToJSON" the compiler won't find the overload, without any warnings. Then again, if you write "istance" instead of "instance" you have the same problem.
  2. Default instances would still require an additional parameter in order to do the inheritance thing.
  3. Can't use the generic "Inline.instance", instead the static method lookup has to be embedded for each overloaded function.

What do you think? Do you see any other pros/cons?

Stackoverflow - need trampolines?

I was just watching this talk and wanted to try to port one of the examples shown in Scala to FsControl / FSharpPlus:

def zipIndex[A](as: List[A]): List[(Int, A)] =
    traverseU(as) { a => for {
        n <- getState[Int]
        _ <- setState(n+1)
    } yield (n, a) }.runS(0)._1

In F#:

open FsControl.Core.Types
open FSharpPlus

let zipIndex (xs: list<'a>) : list<int * 'a> =
    State.eval (traverse (fun a -> monad {
        let! n = State.get()
        do! State.put (n + 1)
        return n, a
    }) xs) 0

The problem with this zipIndex function is that you get a StackOverflowException even with small lists, e.g. zipIndex [5..10000]

Scalaz works around this by using trampolines internally. We should figure out some way to work around this too.

Default instance for Mconcat.

It doesn't pick up the right method.
Here's an extensive test which reproduces the issue.
The problem seems to be that in recursive calls to mconcat it tries to do overload resolution, if the default overload is not yet defined (ie: Tuple2) it delays the resolution (desirable) but once the default is defined (ie: Tuple3) it resolves always to the default.
There must be a way to delay overload resolution.

The description requires a rewrite or clarification

I believe the documentation can be written so that it makes sense to me. Perhaps I am naive. Presently I have no idea what the second paragraph is saying or many subsequent to it (I gave up). I will now turn to the code for an introduction to this library.

Restricted Comonads

We have restricted instances for many method-classes but particularly those for Extract (potential empty lists) might need to be removed.
The reason is that they might fail at runtime, whereas the restricted string instance for Map will fail at compile time.
May be we can create something like TryExtract and then it will be safe to add those instances there.

Traversing infinite sequences

Traversing an infinite list works fine in Haskell: http://ideone.com/GuytMd
But the equivalent F# + FSharpPlus code doesn't terminate and eats infinite memory:

let x = traverse (fun x -> if x > 4 then Some x else None) (Seq.initInfinite id)

This is probably because foldr is currently strict for seq

Maybe a specialized foldr would work here, e.g. http://fpish.net/blog/anton.tayanovskyy/id/1453/http~3a~2f~2fwww.intellifactory.com~2fblogs~2fanton.tayanovskyy~2f2009~2f12~2f11~2fFoldr-or-FoldBack-on-Infinite-F~21sharp~21-Sequences.article

(BTW this stackoverflow question made me realize this).

error FS0192 : internal error : GenUnionRef m

If I upgrade from 1.0.9 to 1.0.10, the F# Compiler (fsc.exe) from 3.1.2 crashes with an internal error complaining with:
error FS0192 : internal error : GenUnionRef m

This is a dependency of Fleece. For now, I've locked us down to version 1.0.9.

Replace doesn't work with Enumerables

This code fails:

> Replace.Invoke { NonEmptyList.Head =  1; Tail =  [2] } { NonEmptyList.Head =  1; Tail =  [] } { NonEmptyList.Head =  100; Tail =  [200] } ;;

  Replace.Invoke { NonEmptyList.Head =  1; Tail =  [2] } { NonEmptyList.Head =  1; Tail =  [] } { NonEmptyList.Head =  100; Tail =  [200] } ;;
  ---------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(3,16): error FS0001: This expression was expected to have type
    'NonEmptyList<'a>'    
but here has type
     'seq<'a>'   

Note: NonEmptyList from F#+

Unzip for seq.

The problem with unzip for seqs as in many other seq functions is the decision to make it strict which would not work for infinite sequences or make it lazy and allow to iterete twice the sequences.
It worth exploring a lazy implementation which caches the iteration as it goes.

Zero

Zero may refer to generic number Zero or to Monad (also Applicative and Arrow) Zero.
In F# we have many numeric types with a Member (Property or Field) Zero and we have the Computation Expression member Zero.
So what should be the meaning of Zero in FsControl?
One possibility is to use it for generic numbers and rename the other one back to mzero.
This will affect One and Plus definitions, to be consistent with Zero.

Folds

The way it is right now the minimal definition for Foldable is the right fold.
This came from the old project, emulating Haskell but here in .NET, with strict evaluation we don't have any benefit of using a right fold as main foldable function.
It would probably make more sense to derive other functions from the left fold, but I was thinking that even more sense would make to derive everything from ToSeq so we can have laziness and if we're lucky derive some lazy functions from that. Another benefit is that IEnumerable is everywhere in .NET collections so we can hope to get more methods derived for free. Any thoughts?

Use of quotation literals.

I was trying to use FsControl in a project that compiles with the standalone option and got the following error:
"The code in assembly 'FsControl.Core' makes uses of quotation literals. Static linking may not include components that make use of quotation literals."

Merge Alternative with MonadPlus.

Alternative and MonadPlus implementations are by convention the same.
In short an Alternative is an Applicative which is also a Monoid and a MonadPlus is a Monad which is also a Monoid.
But here we have no Higher Kinds and no real Type Classes, just Methods so I don't think there is a value of having them separately.
Moreover we should evaluate merging them with ArrowPlus and may be even with Monoid as well, but I think it might be a case when an instance for Monoid and MonadPlus/Alternative is not the same implementation. Indeed instances for Option<'T> are different.

For ArrowPlus I don't know but I guess they will be the same as Alternative/MonadPlus.

Remove MonadTransformers from FsControl

Since the goal of FsControl is to define the overloads for native .NET types and all MonadTransformers are not native, they should be moved out from FsControl to a different project, may be to F#+ or to a dedicated library.
Actually there are other types like Cont, Reader, Writer and State that are here for the sole purpose of "sharing" but that's not 100% the goal of FsControl, so probably makes sense to move them out as well.

BitConversions

I think .NET BitConverter has the same problem as .NET ToString.
The result depends on the current processor endianness.
The problem with ToString was the Culture and we solved it by fixing it to Invariant.
May be we should provide an additional parameter or assume always Little Endian.

Tree structure as an instance of Foldable

I aware that this is probably not the best place to ask a question, but still let me to do. I am trying to rewrite some of the examples in http://learnyouahaskell.com/functors-applicative-functors-and-monoids. I have difficulties with making a tree an instance of Foldable, i.e. I have defined

type Tree<'a> =
    | Empty
    | Node of ('a * Tree<'a> * Tree<'a>)

type Tree with
    static member treeFold (f) (tree:Tree<_>) (z) =
        match tree with
        | Empty -> z
        | Node (x, left, right) ->
            let l = Tree<_>.treeFold f left z
            let r = Tree<_>.treeFold f right z
            let n = f x z
            let res = f (f l n) r
            res
    static member inline instance (_:Foldr, x:Tree<_>, _) = fun (f, z) -> Tree<_>.treeFold f x z

let testTree =
    let one = Node (1, Empty, Empty)
    let six = Node (6, Empty, Empty)
    let three = Node (3, one, six)
    let eight = Node (8, Empty, Empty)
    let ten = Node (10, Empty, Empty)
    let nine = Node (9, eight, ten)
    let five = Node (5, three, nine)
    five

let _11_r32 = foldr (+) 0 testTree
let _11_r33 = foldr (*) 1 testTree

That works. However, this does not

let _11_r33a = foldMap (fun x -> Any (x > 15)) testTree

Am I missing something or have I defined anything incorrectly? Thank you.

No Comonad for Options?

There is no definition for a Comonad for Options which is a Monad and therefore should have a Comonad, No?

Add instances for Seq.

We agree that is not a good idea to mix OOP with this approach.
Anyway, if we think of Seq as a concrete type it's something really nice to have.
As said before, the problem with Seq (but also with other interfaces like IObservable) is that F# does implicit conversions.
If we define a function fmap :: F<'a> -> ('a->'b) -> F<'b> for Seq, we have seq<'a> -> ('a->'b) -> seq<'b> but we can call that function with a List and it will return a seq, so it will be used this way list<'a> -> ('a->'b) -> seq<'b> and that is not the original signature, ideally a code like let (x:seq<string>) = fmap string [1;2;3;4] would not compile, but it does.
This undesired flexibility makes type inference harder.
An approach is not to use interfaces and wrap those types, so we can create a wrapper for seq but then to interact with existing .NET code we have to wrap and unwrap.
I did an experiment. and defined instances for seq, the result is what I mentioned before, and some code using these instances needs more type annotations than the other.
The good news is that I tested all examples and found that existing code still compile as it is, so this does not break anything.
If this is always true, my conclusion is that by adding Seq we are adding the posibility to interact directly with .NET code in a limited way.
And this does not exclude the option of the wrapper, we can provide both at the same time, there will be no conflict.

Monad Transformers example

Based on the paper Monad Transformers Step by Step by Martin Grabmuller, I am trying to come with a solution using FSControl. The data types are defined as follows:

open Haskell
open FsControl.Core.Types

type Name = string

type Exp =
    | Lit of int
    | Var of Name
    | Plus of (Exp * Exp)
    | Abs of (Name * Exp)
    | App of (Exp * Exp)

type Value =
    | IntVal of int
    | FunVal of (Env * Name * Exp)
and Env = Map<Name, Value>

where Haskell is a module defined based on Haskell.fsx example from FSControl examples just to be able to use some functions defined there.
This is the first example with ErrorT which works as expected:

type Eval2<'a> = ErrorT<IO<Either<string,'a>>>
let runEval2 (ev : Eval2<'a>) : Either<string,'a> = runErrorT ev |> runIO

let rec eval2 env exp : Eval2<Value> =
    do' {
        match exp with
        | Lit i -> return (IntVal i)
        | Var n -> match env |> Map.tryFind (n) with
                   | Just val' -> return val'  
                   | Nothing -> return! throwError ("unbound variable" + n)
        | Plus (e1, e2) ->
            let! e1' = eval2 env e1
            let! e2' = eval2 env e2 in
            match (e1', e2') with
            | (IntVal i1, IntVal i2) -> return (IntVal (i1 + i2))
            | _ -> return! throwError "type error in addition"
        | Abs (n, e) -> return (FunVal (env, n, e))
        | App (e1, e2) ->
            let! val1 = eval2 env e1
            let! val2 = eval2 env e2 in
            match val1 with
            | FunVal (env', n, body) -> return! (eval2 (env'.Add(n, val2)) body) 
            | _ -> return! throwError "type error in application"
    }

let expProb2 = eval2 Map.empty p5 |> runEval2

The second example adds ReaderT monad in addition in order to hide the environment. This time however, it does not work correctly:

type Eval3<'a> = ReaderT<Env, ErrorT<IO<Either<string,'a>>>>
let runEval3 env (ev : Eval3<'a>) : Either<string,'a> = runReaderT ev env |> runErrorT |> runIO

let rec eval3 exp : Eval3<Value> =
    do' {
        match exp with
        | Lit i -> return (IntVal i)
        | Var n -> let! env = ask ()
                   match env |> Map.tryFind (n) with
                   | Just val' -> return val'  
                   | Nothing -> return! throwError ("unbound variable" + n)
        | Plus (e1, e2) ->
            let! e1' = eval3 e1
            let! e2' = eval3 e2 in
            match (e1', e2') with
            | (IntVal i1, IntVal i2) -> return (IntVal (i1 + i2))
            | _ -> return! throwError "type error in addition"
        | Abs (n, e) -> let! env = ask ()
                        return (FunVal (env, n, e))
        | App (e1, e2) ->
            let! val1 = eval3 e1
            let! val2 = eval3 e2 in
            match val1 with
            | FunVal (env', n, body) -> return! local (const' (env'.Add(n, val2))) (eval3 body)
            | _ -> return! throwError "type error in application"
    }

let expProb3 = eval3 p5 |> runEval3 Map.empty

Compiler indicates an error at first call to ask function. The logic of the evaluator is the same as in haskell code, so I it must be something wrong in how I use the transformer. Could you please help me indicate what is wrong? Thanks.

Nullable doesn't work.

Nullable instances, doens't seem to be working, even for value types.
I can't remember if it worked before.
Examples:

let (x:Nullable<int>) = pure' 6 ;;

fmap ((+) 9 ) (Nullable 5) ;;

I get always something like:

error FS0193: internal error: GenericArguments[0], 'a', on 'System.Nullable1[T]' violates the constraint of type 'T'.`

If there is no way to fix it, it probably should be removed from the library.

Numeric code needs redesign (II).

First redesign was a first step to get a more F#ish Numeric module.
However many areas were not considered, specifically:

1a) Interaction with arbitrary .NET math operation like DateTime subtraction
1b) Units of measure
2) Integration with F# generic functions like Seq.average which requires a DivideByInt method.
3) Performance of try/safe functions.

Possible solutions:

Implement two set of math operations, a flexible set which will allow adding a TimeSpan to a DateTime and multiply/divide int<m/s> by int<s> and a strict version which will rely in the generic number literals.

Libraries can present modules which will allow to switch (by opening them) between one mode or another.

Integration with existing F# generic functions is probably not possible without redefining those functions, so that alternative should be explored.

Additionally the try/safe-functions use a Result of Exception type, which doesn't throw but eagerly write Exceptions. This could be encoded with a double barrelled CPS version, so implementations of try-versions (option type) will not suffer such performance penalties.

Review extension methods.

By adding a few attributes we add the possibility to use some methods from C# and F#.
However in order to use them:

  • From C# the method should not be generic. Also there is a problem if the method accepts an f# function, it will be tedious to use it.
  • From F# the method should not have dummy arguments, though this is not a technical limitation, they can be used but add lot of noise.

Another issue is than when the containing namespace is opened you see many methods, some of them will not work in C# but it displays everything. I think that's really annoying but an alternative is to remove the extension attribute of the generic methods.

Perhaps extension methods belong to a different project, F# extension methods are already being defined in F#+ so for C# we can create a C#+ project and put them there, adapting the function arguments, there will be a lot of boilerplate code in that project but to the outside world will be clean.

Type Annotation => Runtime Error

Adding a type annotation to the foldable parameter of generic function fold produces a runtime error:
error FS0193: internal error: Object reference not set to an instance of an object.

You can reproduce this error by compiling this version and executing the script Collections.fsx

Wrong constraint in presence of Flexible Types.

There some unwanted flexible types in some signatures:

val inline SeqT.map :
  f:('a -> 'b) -> x:SeqT< ^c> -> SeqT< ^d>
    when (Map or  ^c or  ^d) : (static member Map :  ^c * ('e -> seq<'b>) *
                                                    Map ->  ^d) and
         'e :> seq<'a>

Specifically the last constraint 'e :> seq<'a> is unwanted and makes no sense.

We had this problem in the past and this is the way it was solved.

Here that constraint seems to be coming from a map of map, a quick test:

let map f m = Option.map (Seq.map f) m
val map : f:('a -> 'b) -> m:#seq<'a> option -> seq<'b> option

Which can be solved this way:

let map f m = Option.map (Seq.map f : (seq<_>->_)) m
val map : f:('a -> 'b) -> m:seq<'a> option -> seq<'b> option

Eq typeclass?

I was also wondering about the potential usefulness of an Eq typeclass. I'm not sure it would be very useful, as F# already enforces proper equality for =, and this runs deep in all of .NET.

But it might be useful to express conditional equality (not sure if the term is correct).
Concretely, I couldn't find a good way to express Eq a => Eq (Tree a) (as in http://hackage.haskell.org/package/containers-0.3.0.0/docs/Data-Tree.html ) in my port of Data.Tree ( https://github.com/fsharp/fsharpx/blob/master/src/FSharpx.Collections.Experimental/RoseTree.fs ), and an Eq typeclass might help.

What do you think?

License

Hi, I would like to use FsControl in one of my open source projects. Would you mind adding a license to the project that clarifies on which terms FsControl can be used?

Lazy binding not 100% lazy.

This is a common problem when defining Monads in strict languages.
The semantics are the same but as long as there are no side-effects involved.
Here's an example and a way to workaround it:

let bind (f:_->Lazy<_>) (x:Lazy<_>) = f x.Value
let join (x:Lazy<Lazy<_>>) = x.Value

// vs
let bind' (f:_->Lazy<_>) (x:Lazy<_>) = lazy (f x.Value).Value
let join' (x:Lazy<Lazy<_>>) = lazy( x.Value.Value )

// test bind
let v5: Lazy<_> = lazy (printfn "5 !!! "; 5)
let fPlus10 x   = lazy  (printfn "add 10 !!! ";x + 10)
let v5plus10    = v5 |> bind fPlus10    // it prints "5 !!!"  here
let v15 = v5plus10.Force()              // not here, it prints only "add 10 !!!"

let v5': Lazy<_> = lazy (printfn "5 !!! "; 5)
let fPlus10' x = lazy  (printfn "add 10 !!! ";x + 10)
let v5plus10'  = v5' |> bind' fPlus10'  // prints nothing
let v15' = v5plus10'.Force()            // it prints "5 !!!" "add 10 !!!"

// test join
let v4ll: Lazy<_> = lazy (printfn "outer !!! ";lazy (printfn "inner !!! "; 4))
let v4l = join v4ll                     // it prints "outer !!! "
let v4  = v4l.Force()                   // it prints "inner !!! "

let v4ll': Lazy<_> = lazy (printfn "outer !!! ";lazy (printfn "inner !!! "; 4))
let v4l' = join' v4ll'                  // prints nothing
let v4' = v4l'.Force()                  // it prints outer and inner

Merge FsControl into F#+

Many people wonder why FsControl and F#+ are 2 separate projects.

FsControl is basically an overload repository organized into 'Invokable Types' and F#+ are F# Extensions, not necessarily related to overloads.

However, F#+ could include the overloads as part of the extensions it offers.

The problem was that before it was intended to facilitate integration between 'monadic' projects that don't want to depend on F#+ but remain compatible. Then these projects only needed to depend on FsControl.

But now, with the so called 'friendly signatures' there's no need to depend on any project at all. The only thing a 'monadic' library should do in order to be able to integrate with generic operators is to add a static method with the right signature, which will not contain any class from FsControl. Before they needed to contain a dummy parameter from FsControl within the Invokable.

Advantages of Merging both projects

  • Would solve the problem of the cyclic dependencies: FsControl needs efficient implementations for primitive type A, F#+ has that efficient implementation, since it offers extensions methods, but FsControl cannot depend on F#+ since F#+ depends on FsControl.

  • Nowadays projects that use F#+need to depend also on FsControl, so 2 dependencies instead of 1.

  • Maintaining both projects will be much easier as a single unit.

Open questions:

  • Would merging both projects bring back State, Reader to the Invokable Type or is it good as it is now as an independent entity?

Unsolved type variable in tests

Getting these compilation errors in the tests... are you also getting them? I'm using F# 3.1.2

C:\prg\FsControl\FsControl.Test\UnitTest.fs(107,25): error FS0073: internal error: Undefined or unsolved type variable: ^_?3062019
https://github.com/gmpl/FsControl/blob/master/FsControl.Test/UnitTest.fs#L107

C:\prg\FsControl\FsControl.Test\UnitTest.fs(149,28): error FS0073: internal error: Undefined or unsolved type variable: ^_?3062492
https://github.com/gmpl/FsControl/blob/master/FsControl.Test/UnitTest.fs#L149

C:\prg\FsControl\FsControl.Test\UnitTest.fs(150,28): error FS0073: internal error: Undefined or unsolved type variable: ^_?3064361
https://github.com/gmpl/FsControl/blob/master/FsControl.Test/UnitTest.fs#L150

A name that markets it better to F# users.

I left a comment on StackOverflow:

In the last few days I ran into references for FsControl a few times so I finally stated looking at it closely and like what I see. If you had only given it a better name I might have been using it for a few years now. Every time I saw FsControl I would think Windows Form controls and say, I don't need this. I give it vote to have a name change. :)

and received:

I agree. Control comes from the Haskell libraries that inspired the project but I would be happy to put a better name, I invite you to open an issue suggesting a name change. โ€“ Gustavo

I don't have any ideas for a better name at present, but firmly believe that people using F# should be aware of this. In reading the examples some of the fog (no pun intended) I had with F# started to disappear.

Id bind is not correct

static member instance (Bind, x:Id<'a> , :'b Id ) = fun (f:->Id<'b> ) -> Id(f x)

should be
static member instance (Bind, x:Id<'a> , :'b Id ) = fun (f:->Id<'b> ) -> f x.getValue

Collection

I've never seen something like a Collection type class before.
I'm not really convinced, but at the moment don't know where these type methods belong otherwise.
However ToList and Filter might fit well in the module Foldable.

Custom type class

I have recently seen a little example in Scala how write a generic "library" using type classes (http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html). It consists of math (including the interface) and statistics module. The approach of course takes an advantage of high order types in Scala. Math module with the default implementations:

object Math {
  trait NumberLike[T] {
    def plus(x: T, y: T): T
    def divide(x: T, y: Int): T
    def minus(x: T, y: T): T
  }
  object NumberLike {
    implicit object NumberLikeDouble extends NumberLike[Double] {
      def plus(x: Double, y: Double): Double = x + y
      def divide(x: Double, y: Int): Double = x / y
      def minus(x: Double, y: Double): Double = x - y
    }
    implicit object NumberLikeInt extends NumberLike[Int] {
      def plus(x: Int, y: Int): Int = x + y
      def divide(x: Int, y: Int): Int = x / y
      def minus(x: Int, y: Int): Int = x - y
    }
  }
}

and the Statistics module:

object Statistics {
  import Math.NumberLike
  def mean[T](xs: Vector[T])(implicit ev: NumberLike[T]): T =
    ev.divide(xs.reduce(ev.plus(_, _)), xs.size)
}

At this point, the mean function is generic enough so that it can be used with int or double.

Trying to simulate this in F# inspiring by FsControl style, I end up writing each method as a type:

module Math =

    type Plus = Plus with
        static member instance (Plus, x:int, _:int) = fun y -> x + y
        static member instance (Plus, x:float, _:float) = fun y -> x + y 
    type Minus = Minus with
        static member instance (Minus, x:int, _:int) = fun y -> x - y
        static member instance (Minus, x:float, _:float) = fun y -> x - y 
    type Divide = Divide with
        static member instance (Divide, x:int, _:int) = fun y -> x / y
        static member instance (Divide, x:float, _:float) = fun y -> x / y
    type Length = Length with
        static member instance (Length, xs: int list, _: int) = fun () -> xs.Length
        static member instance (Length, xs: float list, _:float) = fun () -> xs.Length |> float

    let inline internal plus x y = Inline.instance (Plus, x) y
    let inline internal minus x y = Inline.instance (Minus, x) y
    let inline internal divide x y = Inline.instance (Divide, x) y
    let inline internal length xs = Inline.instance (Length, xs) ()   

And simple example:

open Math
let r1 = plus 12 34
let r2 = plus 12.0 34.0

That works well until you want to use it in the function which shall be generic:

module Statistics =
    let mean (xs : 'a list) =
        let sum = xs |> List.reduce (plus) in divide sum (length xs)

The issue is the restriction of the list element type. The compiler infers the type of the list elements by the first usage of the function, i.e in this case the type is float and using the function with different type will cause compilation error:

open Statistics
let r3 = mean [13.; 23.; 42.; 45.; 61.; 73.; 96.; 100.; 199.; 420.; 900.; 3839.]
//let r4 = mean [13; 23; 42; 45; 61; 73; 96; 100; 199; 420; 900; 3839] // This does not compile

So, I wonder whether this scala example might be written at all in any way using the FsControl style or does it require completely different approach? Thank you.

Type class constraint

I tried to create a custom type class (YesNo type class) according to http://learnyouahaskell.com/making-our-own-types-and-typeclasses#a-yes-no-typeclass. What I was able to do is the following:

type YesNo = YesNo with
    static member instance (_YesNo:YesNo, x:int, _) = fun () ->
        match x with
            | 0 -> false
            | _ -> true
    static member instance (_YesNo:YesNo, ls:List<_>, _) = fun () ->
        match ls with
            | [] -> false
            | _ -> true
    static member instance (_YesNo:YesNo, b:bool, _) = fun () -> b
    static member instance (_YesNo:YesNo, m:Maybe<_>, _) = fun () ->
        match m with
            | Just _ -> true
            | Nothing -> false

let inline yesno x = Inline.instance (YesNo, x) ()

let inline yesnoIf yesnoVal yesResult noResult =
    if yesno yesnoVal then yesResult
    else noResult

I wonder whether there is a way how to enforce type class constraints in function signature similarly to haskell, e.g. in the example of YesNo type class, the function signature may be:

yesnoIf :: (YesNo y) => y -> a -> a -> a

(notice the YesNo constraint). I was only able to specify the function as inline. However, as the function contract is not explicit, it might be difficult for other developers to read the code at first sight.

I may be wrong with the code above or I missed something. Or what I am suggesting is not possible at all. Any detail to this would be appreciated. Thank you.

Can not build with F#4.0/VS2015 - FS3186 error reading F# metadata node

I have a feeling that this is going to be difficult to sort out, as I can't reproduce it in a new project. I thought I'd report it in case you had any tips for me to work around it.

I have a project that depends on Fleece. The build fails on VS2015/F#4.0 with the following error:

FS3186: An error occurred while reading the F# metadata node at position 878 in table 'ivals' of assembly 'FsControl.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. The node had no matching declaration. Please report this warning. You may need to recompile the F# assembly you are using.

Dependencies:

  <package id="Fleece" version="0.4.0" targetFramework="net4" />
  <package id="FsControl" version="1.0.9" targetFramework="net4" />
  <package id="FSharpPlus" version="0.0.4" targetFramework="net4" />

Builds fine with Microsoft Build Tools 2013 / VS2013.

Edit 2016-04-05:
Workaround: add nowarn.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.