Giter Site home page Giter Site logo

algebra's Introduction

Build Status Coverage status Gitter Maven Central

algebra

current status

The code in this repository was moved into Cats in cats#3918. All future development will occur there. Algebra will continue to release under the same artifact name and maintain binary compatibility with the 2.x series.

the vision

This repo represents an attempt to unify the basic algebraic type classes from Spire and Algebird. By targeting just these type classes, we will distribute an algebra package with no dependencies (except for cats-kernel) that works with Scala 2.11 and 2.12, which can be shared by all Scala libraries interested in abstract algebra.

Since the creation of Algebra, we have also decided to interoperate with the Cats project. Algebra and Cats interoperate using the cats-kernel module.

See the Algebra website for more information. The latest API docs are hosted at Algebra's ScalaDoc index.

getting algebra

Algebra supports Scala 2.11, 2.12 and 2.13 and is available from Sonatype (and Maven Central). In addition to the JVM, Algebra also supports Scala.js.

To use algebra in your own projects, include this snippet in your build.sbt file:

libraryDependencies += "org.typelevel" %% "algebra" % "2.0.0"

If you want to use Algebra's laws, you can include those as well with this snippet:

libraryDependencies += "org.typelevel" %% "algebra-laws" % "2.0.0"

what we have so far

This repo has been seeded with most of the contents of spire.algebra, and has been modified to fit an initially-conservative and shared vision for algebraic type classes. Discussions over removals and additions should take place on the issue tracker or on relevant pull requests.

Projects using Algebra

participants

Anyone who wants to participate should feel free to open issues or send pull requests to this repo.

The following people are Algebra maintainers (i.e. have push access):

development process

Please make a pull request against the master branch. For those who can merge pull requests, we follow these rules:

  1. Do not merge your own PR unless N people have signed-off on the PR (e.g. given a thumbs-up, +1, shipit, etc) and Travis is green.

  2. If you are not the author, and you see (N - 1) sign-offs and Travis is green, just click merge and delete the branch.

  3. Currently, N = 2.

algebra overview

Algebra uses type classes to represent algebraic structures. You can use these type classes to represent the abstract capabilities (and requirements) you want generic parameters to possess.

For a tour of the Algebraic structures that algebra offers, see the extensive overview on the Algebra website.

Code of Conduct

See the Code of Conduct

Copyright and License

All code is available to you under the MIT license, available at http://opensource.org/licenses/mit-license.php and also in the COPYING file.

Copyright the maintainers, 2015-2016.

algebra's People

Contributors

adelbertc avatar alistair-johnson avatar arashi01 avatar armanbilge avatar asakaev avatar benhutchison avatar ceedubs avatar christopherdavenport avatar clydemachine avatar coltfred avatar cquiroz avatar denisrosset avatar durban avatar erik-stripe avatar fagossa avatar jhnsmth avatar johnynek avatar kailuowang avatar larsrh avatar non avatar pjan avatar pleira avatar rklaehn avatar sritchie avatar sritchie-stripe avatar thomas-stripe avatar tixxit avatar tomasmikula avatar travisbrown avatar xuwei-k 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

algebra's Issues

Default instances

I think the basics are in place (even well beyond the basics). But one thing we have not totally discussed is default instances.

Algebird, unlike Spire, gives default instances for almost everything. People are almost never surprised, but it does mean that Semigroup[Int] is addition (not max, or min or multiplication, or xor or and). I know you guys disagree about that choice so let's set that aside.

What about Semigroup[(A, B)]. To me, by default that should be combine on A and B in a tuple.

What about Eq[(A, B)], List[A], Map[K, V]? Again, those seem unambiguous to me.

Without these, users immediately start writing combinators to do anything of use.

Suppose we do add these. How do we implement them? In algebird we use code gen at compile time (in some cases, some are still the old way) to generate 22 tuple instances. A modern way might be to use macros. That has issues with the separate compilation requirements. I lean towards code-gen for these things.

I'd like to see code-gen versions for Eq, PartialOrder, Order for Tuples. I'd like to see default instances of those for sequences and primitives as well.

How does this sound?

Type class instances for tuples

Particularly useful when doing single-pass folds, such as in Monoid#combineAll

Type classes that can be defined off the top of my head:

  • Semigroup
  • Monoid
  • Eq
  • Order

Set instances

From cats Gitter:

@fsvehla want to open an issue at https://github.com/non/algebra/ ?

Breeze Iterop and merger of effort

Is it possible to work more closely with Breeze also so that there will not be any fragmentation of linear algebra libraries. There is much overlap in the area.

Also other type level products. Perhaps the afterwards both projects can be brought under type level also.

Definitions for partial algebras

Over in Spire, @denisrosset is submitting a PR to add partial algebras.

(Essentially, these operations would provide partialCombine(A, A): Option[A] instead of the more usual combine(A, A): A.)

The most natural way to do this is to make Semigroupoid[A] a parent of Semigroup[A], PartialMonoid[A] the parent of Monoid[A], and Groupoid[A] the parent of Group[A]. However, if Algebra doesn't want to add partial algebras, then obviously this would not be possible, and instead we would need to provide conversions from Group[A] => Groupoid[A] and so on.

What do you all think?

more packages?

we could break core into algebra-core, algebra-ring (depends on core), algebra-lattice (depends on ring).

It might be easier to maintain binary stability in a smaller algebra-core which has fewer concepts, which are incidentally the ones most commonly used in Cats, Algebird, Scalding and Summingbird.

Magma and a property as trait based approach.

So looking at our table in the readme, you might notice that all structures are associative. We could say that a Semigroup is an associative Magma:

trait Magma[T] {
  // no law here other than closure, which the type-system guarantees.
  def combine(a: T, b: T): T
}

If we had this, then on binary operations we could just have some traits like:

trait Associative[T] extends Magma[T]
trait Commutative[T] extends Magma[T]
trait Idempotent[T] extends Magma[T]

We can keep the named entities, but it would be nice to have a method like:

object Semilattice {
  def from[T](t: Idempotent[T] with Commutative[T] with Associative[T]): Semilattice[T] = ...
}

object Band {
  def from[T](t: Idempotent[T] with Associative[T]): Band[T] = ...
}

Just a thought. Then the situation we got into with Ring is clearer too: we have traits for all properties that extend some root type: RingLike[T] or something that has plus and times. Then we have a bunch of traits for that table. We still name the common ones, but it is clear how to express any set of properties, even if we don't have a formal name for that type. And it easy to get an instance of named type by satisfying the properties.

Semigroup/Monoid.combineN: Express partiality with values not exceptions

After reading http://plastic-idolatry.com/erik/sw2015.pdf it looks like
Semigroup.combineN and Monoid.combineN currently only meet goal number 7 (Pragmatic) but not goal number 2 (Safe: Express partiality with values not exceptions).

  /**
   * Return `a` combined with itself `n` times.
   */
  def combineN(a: A, n: Int): A =
    if (n <= 0) throw new IllegalArgumentException("Repeated combining for semigroups must have n > 0")
    else repeatedCombineN(a, n)

Add a algebra-test package with scalacheck laws

One thing we did in algebird was make an algebird-test package. Here we defined thinks like def monoidLaws[T: Arbitrary: Monoid]: Prop so users could easily test their monoids just by making an Arbitrary for their type.

It would be really nice to have something like this. If we want to generalize:

trait Law[C[_]] {
  def apply[T](structure: C[T], arb: Arbitrary[T]): Prop
}

Then we could test triples like: List(MonoidLaw, ListMonoid, implicitly[Arbitrary[List[Int]]], ...)

support optional by-name RHS parameters

We had talked about having a variant of combine which was by-name in the right-hand side parameter. By default it would dispatch to the strict combine but this would allow other implementors to override this and change the behavior.

Add byAll and fromAll to Eq/PartialOrder/Order

Something that I've received requests for is an easier way to define these instances.

Here's an example of what I mean (assume we can't automatically derive instances for case classes/products):

case class Foo(a: Int, b: String, c: Int)

// a function is used if the previous function returned 0/EQ
val o1: Order[Foo] = Order.fromAll[Foo](
  (x, y) => x.a compare y.a,
  (x, y) => x.b compare y.b,
  (x, y) => x.c compare y.c)

// here's an even more terse version that will use Order[Int] and Order[String]
val o2: Order[Foo] = Order.byAll(_.a, _.b, _.c)

The logic in both cases is that the first function is used -- and if the items are equal, the next one is used, otherwise the result returns immediately. If after the last function runs they are equal, then 0/EQ is returned.

Add EqK, SemigroupK, and MonoidK?

Currently the "kinded" versions of Eq, Semigroup, and Monoid (that is, EqK, SemigroupK, and MonoidK) live in Cats. Should they live in Algebra to be with their non-universal counterparts?

One benefit of having the K versions in Algebra is that we could add a conversion like implicit def fromEqK[F[_]:EqK, A:Eq]: Eq[F[A]] in the Eq companion object (and similarly for Semigroup and Monoid). Right now we can define these in Cats, but we don't have a companion object we could add them to where implicit search would find them.

Heyting#asCommutativeRing broken

Heyting#asCommutativeRing seems to be broken. The problem is with the negate method: complement is not an inverse with respect to xor.

As an example, consider the usual interpretation of the type Boolean = {false, true} as a Boolean algebra.

From the additive group, we have the law

plus(x, negate(x)) = zero

Substituting one for x we get

plus(one, negate(one)) = zero

And now replace plus by xor, negate by ¬, zero by false and one by true (as defined in asCommutativeRing):

xor(true, ¬true) = false

i.e.

xor(true, false) = false

which is a contradiction.

FWIW, I don't immediately see how this could be fixed, i.e. I don't see how every Heyting algebra gives rise to a commutative ring.

Automatic style-checking and/or scalariform rewriting

I have a branch which adds style-checking and Scalariform.

How do people feel about this? If we are going to do this, it will require one big PR to get all the warnings dealt with and the code reformatted.

I think Scalastyle shouldn't be too contentious. I've started using it on other projects and it should be easy to find a rule set that we can all live with.

As far as Scalariform, I seem to recall @johnynek and @avibryant both saying positive things about it. Running a test, the only change which I don't love is that:

tpls.map { case (x, y) =>
  ...
}

is rewritten to:

tpls.map {
  case (x, y) =>
    ...
}

But I can live with this if everyone else wants to move in this direction.

is lattice a distributive lattice?

Here we say yes:

"Additionally, join and meet distribute:"

https://github.com/non/algebra/blob/master/core/src/main/scala/algebra/lattice/Lattice.scala#L16

But here we don't test this property:
https://github.com/non/algebra/blob/master/laws/shared/src/main/scala/algebra/laws/LatticeLaws.scala#L39

Lastly, a BoundedLattice is also a rig, right:
https://github.com/non/algebra/blob/master/core/src/main/scala/algebra/lattice/BoundedLattice.scala

we have the distributive + associative laws, we have 0, 1. Am I missing something?

So, the negation (which is identity, it looks like) is somehow only in Bool?

related to #89

instances for vector

Inspired by @ceedubs' PR (thanks btw) I was inspired to start thinking about vectors. There are different interpretations of vectors of different lengths. For example, are vector implicitly padded by a zero value (i.e. sparse) or not? Is the order of the values significant or not (i.e. should we prefer lexicographic orders)? Should we support pair-wise operations beyond the usual things like vector addition?

Here's what I have so far:

Eq[A] => Eq[Vector[A]]

  • Exact: every element must match
  • Sparse: trailing zeros are implied (required Monoid[A])

PartialOrder[A] => PartialOrder[Vector[A]]

  • Lexicographic: first non-equal field determines result
  • Conservative: all positions must have the "same" relationship or NaN is returned
  • (Exact vs Sparse distinction applies to both variants)
  • (Another possible impl could use distance metric)

Order[A] => Order[Vector[A]]

  • Lexicographic: first non-equal field determines result
  • (Exact vs Sparse distinction applies)
  • (Another possible impl could use distance metric)

Semigroup[A] => Semigroup[Vector[A]]

  • Strict: lengths must match or error
  • Hand-wavy: longer vector fills in tail automatically

Monoid[A] => Monoid[Vector[A]]

  • Sparse: empty vector is identity element (multiple equiv reprs -- needs consistent eq/order)
  • (Exact impl would require a "size" param, couldn't be implicit)

Group[A] => Group[Vector[A]]

  • (Same basic situation as for monoid)

Anyway, I am inclined to try to simplify the picture by making sparse/lexicographic the defaults. The nice thing there is that we can provide efficient, reasonable definitions implicitly without hassling the user. The downside is that it could mask potential size errors. I've had situations where a pairwise Field[Vector[A]] would have been useful, but I think it would be more idiomatic to use a case class or tuple for that situation in Scala, so I'm happy to leave that alone for now.

I will look at how Algebird currently does this. @johnynek, what are your thoughts here?

maybePlus

This pattern comes up a lot in my code:

val here: V
val opt : Option[V] = ??
opt.map { v => Semigroup.plus(v, here) }.getOrElse(here)
// or:
Monoid.plus(opt, Some(here)).get // can't throw

Is it worth having:

object Semigroup {
  def maybePlus[T:Semigroup](mb: Option[T], t: T): T
}


Consider Semiring definition

So @luc-j-bourhis (from #spire-math) did some research into the literature around various Ring-like structures and produced this gist:

https://gist.github.com/luc-j-bourhis/ffd0cccf4f83b1b8a133

He is discussing Spire but we are currently using the same definitions.

It's an interesting read but the only really major finding is that he thinks we should change Semiring. Currently our Semiring is a monoid for + and a semigroup for *. He thinks both should be semigroups.

What do you all think? It's an easy change to make if it seems good. I feel like @tixxit and I had a reason to prefer the current definition but honestly I can't really remember it.

Wiki describing properties and algebraic objects

One of my hopes is that this project can introduce more programmers to the value of algebra in many domains. I don't expect them to have studied much math before, but I do expect them to be willing to read and learn new terms.

I think it would be nice to build a table of properties: (commutative, associative, idempotent, etc...), describe what they are, and then have a table, or a list of objects that satisfy them in some way. Generally we are speaking about binary operations here, but sometimes we talk about pairs of operations (e.g. distributive).

I think it would be valuable to have a page that sells some of the top most useful structures: (Semigroup enables parallelism, commutative enables reordering which enables parallelism in a different context, idempotent is highly useful in distributed systems, etc...)

Consider publishing under org.typelevel instead of org.spire

This is mostly administrative, but given that we are trying to generalize Spire, publishing under org.spire-math might be a bit weird.

I don't think this issue would affect who has push access to the repo, or anything else, besides associating the project with Typelevel and changing the artifact ID.

What do you all think?

Add a Mima test for core

discussed in #18. I think we should be SUPER conservative with algebra-core, which if we succeed with this, could be a dependency of spire, algebird, and transitively scalding and summingbird (perhaps spark would use it if we can gain traction as a stable abstraction for algebraic concepts).

With mima, we could make sure we fail the build if there is any binary compatibility issue with changeds to algebra-core.

We can probably be a bit more free with algebra-std assuming that is less often a direct dependency.

submit Priority to scala.util.Priority?

I copied https://github.com/non/algebra/blob/master/core/src/main/scala/algebra/Priority.scala into algebird because I wanted to resolve an issue with algebird + spark and spark's approach of using implicit ord: Ordering[K] = null with the fact that you can't in 2.11 have overloaded methods and default parameters (so I used Priority[Ordering[K], DummyImplicit] and .getPreferred.orNull).

It occurs to me, this could be a candidate to add to scala. It is unlikely to change much.

If they'd never accept it, no big deal, but it seems to be one of the easier things to move there.

Modularize algebra

So despite never being released yet we've already hit complaints about algebra's size! 😉

The currently hope is that we can split algebra into algebra-core and then possibly algebra-lattice and algebra-ring. I'm not sure how algebra-number fits into this. I think that "core" is the most important, so worst-case we could have "core" and "everything else".

Would be sweet to use PRs

I see the pushes, but not as PRs.

What if we start using PRs to be able to comment on code before it is merged?

Add benchmarking project

It would be good to have a benchmarking project defined. This would allow us to do a few things:

  1. Get benchmarks for std instances.
  2. Confirm that miniboxing/specialization is working correctly.
  3. Avoid performance regressions for helper methods.

What do you all think? Spire has done this and it's been really useful over the years.

Publish a style/design guide for algebra

It doesn't have to be very long, but I think it would be smart to explicitly document:

  • goals (and non-goals) for the project, to be explicit about scope.
  • design principles, to explain why we built it the way we did.
  • expected usage patterns, to show how we imagine folks using this.
  • expected extension patterns, to show how folks can fill in gaps or build on this.
  • some basic code guidelines, to aid consistency
  • high-level explanation about law-checking, and how we verify particular laws.

There is a little bit of this in Spire right now, but we could probably use more there, and since this project has a more limited scope it should be easier to do it here.

add sum or sumOption to Semigroup

def sum(t: TraversableOnce[V]): V

on Hadoop, this might be an Iterator of 10^9 elements, so Once is important.

For boxing, we might not want Option[V]. Don't pass an empty iterable to this method, else undefined.

Or, we could do sumOption (as Algebird did) and return Option[V].

yea, nay?

Type classes for Boolean ring and Boolean algebra without 1.

There are useful data types that are almost like Bool or BoolRing, except they don't have a top element. A good example is Set[A]—when A is a type with infinitely many inhabitants, we cannot have the top element (Set of all As), but it is still useful to view it as a Boolean algebra.

Naming

A suitable name for a BoolRing without identity seems to be BoolRng.

For Bool without top, the best I have so far is ToplessBool. I'm not completely satisfied with this name, because it might suggest Bool necessarily without top, while what we mean is Bool potentially without top.

Definitions

BoolRng is just a Rng with idempotent multiplication (a⋅a=a).

ToplessBool is a DistributiveLattice with bottom and for all elements a, b, there is an element b\a, called the relative complement of a in b, such that

  1. a ∧ b\a = 0
  2. a ∨ b\a = a ∨ b

Note that in the presence of 1, we can define ¬a = 1\a and the above laws give the familiar laws of Boolean algebra:

a ∧ ¬a = a ∧ 1\a = 0
a ∨ ¬a = a ∨ 1\a = a ∨ 1 = 1

Equivalence

BoolRng and ToplessBool are equivalent.

Given a ToplessBool, one can construct a BoolRng in the following way:

  • 0 = 0
  • a⋅b = a∧b
  • a+b = a\b ∨ b\a
  • -a = a

Given a BoolRng, one can construct a ToplessBool in the following way:

  • 0 = 0
  • a∧b = a⋅b
  • a∨b = a+b+(a⋅b)
  • a\b = (a+b)⋅a = a + a⋅b

Add Show typeclass

This might be a bit controversial, since Show is not really "algebraic". But I think that algebra-core has the potential to become something like the predef for people working with typeclasses.

I would like to have a typeclass-based alternative to everything in java.lang.Object in algebra-core. Eq already exists. There is issue #38 for adding a simple hashing typeclass. So that leaves Show.

There is a Show in cats: https://github.com/non/cats/blob/master/core/src/main/scala/cats/Show.scala . Maybe just move that one level up?

Publishing, versioning

I was thinking it might be good to publish a series of releases (0.0.x) and make branches of algebird and spire that pull those jars. We might turn up some issues at that that point and want to make quick fixes.

I think when we have versions of 0.0.x that compile for both Spire and Algebird, we could publish 0.1.0 and then publish new versions of Algebird and Spire to use those.

Next, it would be great to use Mima to enforce no binary incompatibilities between x.y.z and x.y.z'. We struggled with binary incompatibility issues for a long time until we got more rigorous about such testing. Recently, on the x.y develop branches have mima running as part of the travis tests so we can introduce breaks when there should be minor improvements.

specialization cost

I am pretty dubious the specialization on Boolean and Byte is going to help at all, but it is going to increase the method count of all the traits that specialize in that way, unless I am mistaken.

The reason I don't think it is needed is that boxing a Boolean is just an if/else without allocation, and boxing a Byte is just looking up a 256 length static array (which should be in cache if you are doing this a bunch, I would expect).

It might be nice to have some kind of linter to check that we specialize all the traits the same way (just Short, Int, Long, Double, Float?).

Add BoolRing type class

This is a proposal to add type class for Boolean rings.

A Boolean ring is a ring that satisfies x times x = x for all x (i.e. every element is idempotent with respect to multiplication).

There isn't general consensus whether a Boolean ring assumes 1 (multiplicative identity). Some sources refer to Boolean ring as a Boolean algebra without identity. However, since algebra.ring.Ring has 1, it makes sense for BoolRing to include 1 as well. Adding a Boolean ring without 1 could be addressed as a separate issue, possibly calling it BoolRng.

The above property implies:

  1. Every Boolean ring is a commutative ring.
  2. Every element is its own additive inverse, i.e. x plus x = 0.

As a consequence of 1., BoolRing should extend algebra.ring.CommutativeRing.

As a consequence of 2., BoolRing can implement negate to be

def negate(x: A): A = x

A Boolean ring is equivalent to a Boolean algebra, with conversions both ways.

Bool#asCommutativeRing already returns a Boolean ring. However, this fact is currently not captured by the return type.

My opinion about TypeClasses

I like this pattern:

trait TClass[T] {
  def methodOne[R](t: T): R
  def methodTwo(t1: T, t2: T): T
  // a bunch more:
}

//ALL of the methods on TClass appear below with an implicit parameter:
object TClass {
  // prefer to call as: TClass.methodOne(t) and use implicit resolution
  def methodOne[T,R](t: T)(implicit tclass: TClass[T]): R = tclass.methodOne(t)

  def methodTwo[T](t1: T, t2: T)(implicit tclass: TClass[T]): T =    
    tclass.methodTwo(t1,t2)
}

My thinking is that we should follow this rule for each Typeclass. Is there any reason not to?

Clarify usage of Eq with case objects and trait

Hi all, I just came to this project after reading Eugene Yokota's intro to Cats' Eq typeclass, which was linked from this week's Scala Times.

I was wondering if that page could be improved by asking you folks:

  1. Is there a better way to use Eq directly with a sealed trait and case objects, which doesn't require the boiler plate in that article?
  2. Do you have a comment on the mixing of Equality and Equivalence that he brings up?

Thanks for any attention to these questions,
-Marc

/cc @eed3si9n

Improve README.md

I sort of threw together the README when this project was first starting.

I think we're starting to have a more concrete idea about the project, so ideally we could flesh this out a bit. Oscar's guide on how to merge PRs could be expanded into what we expect to include (or leave out) of the library, design philosophy, as well as a process for how to contribute (and more importantly, where and how to discuss potential contributions).

Also, I'd like to bring this project under the Typelevel Code of Conduct. Any objections?

Use macros to remove duplicate between tests and names

Our tests have a lot of lines like these:

checkAll("List[Int]", OrderLaws[List[Int]].order)
checkAll("List[Int]", GroupLaws[List[Int]].monoid)
checkAll("List[String]", OrderLaws[List[String]].order)
checkAll("List[String]", GroupLaws[List[String]].monoid)

In addition to being annoyingly repetitive these calls introduce the very real possibility that the label and the actual code being run can be in disagrement.

It would be nice to use a macro (or similar) to remove the duplication.

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.