FAQ
Hello

I've seen people lamenting the lack of functional tools in Go, the sort of
map / filter / fold / reduce. I've also seen half-baked attempts that force
the user to litter their code with type assertions or to use special
container types.

This is a fully concurrent implementation of Map and Filter on arbitrary
slices, that can be used without any type assertions, reflection, or
special container types on the part of the user.

https://github.com/tobia/fn

http://godoc.org/github.com/tobia/fn


The code is tested (85%) but has not seen production use.

Please let me know what you think of it.

My time is limited, but I'd like to add more tools in the future (starting
with Fold / Reduce), more data types (maps), and/or more concurrency levels
(limiting the number of workers.)

-Tobia

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

  • Egon at Dec 15, 2013 at 5:19 pm

    On Sunday, December 15, 2013 6:35:04 PM UTC+2, Tobia wrote:
    Hello


    I've seen people lamenting the lack of functional tools in Go, the sort of map / filter / fold / reduce. I've also seen half-baked attempts that force the user to litter their code with type assertions or to use special container types.


    This is a fully concurrent implementation of Map and Filter on arbitrary slices, that can be used without any type assertions, reflection, or special container types on the part of the user.



    https://github.com/tobia/fn


    http://godoc.org/github.com/tobia/fn


    The code is tested (85%) but has not seen production use.


    Please let me know what you think of it.


    My time is limited, but I'd like to add more tools in the future (starting with Fold / Reduce), more data types (maps), and/or more concurrency levels (limiting the number of workers.)


    -Tobia
    Please add examples of problems this package solves. Currently it just shows the usage and has some vague statements about problems of understanding wg-s and channels.

    + egon

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Andrew Gallant at Dec 15, 2013 at 5:31 pm
    You may find use for a rudimentary type checker: https://github.com/BurntSushi/ty

    The "fun" sub package provides functions written with that type checker. (It is different from your package in that a single type assertion is required on the return value of a function.)

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Egon at Dec 17, 2013 at 1:06 pm
    I believe it's possible to do something
    simpler: http://play.golang.org/p/kDoOJijq3A
    Also, it's more "type-safe" at compile time and faster.

    + egon
    On Sunday, December 15, 2013 6:35:04 PM UTC+2, Tobia wrote:

    Hello

    I've seen people lamenting the lack of functional tools in Go, the sort of
    map / filter / fold / reduce. I've also seen half-baked attempts that force
    the user to litter their code with type assertions or to use special
    container types.

    This is a fully concurrent implementation of Map and Filter on arbitrary
    slices, that can be used without any type assertions, reflection, or
    special container types on the part of the user.

    https://github.com/tobia/fn

    http://godoc.org/github.com/tobia/fn


    The code is tested (85%) but has not seen production use.

    Please let me know what you think of it.

    My time is limited, but I'd like to add more tools in the future (starting
    with Fold / Reduce), more data types (maps), and/or more concurrency levels
    (limiting the number of workers.)

    -Tobia
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Tobia at Dec 17, 2013 at 11:12 pm

    On Tuesday, December 17, 2013 2:06:04 PM UTC+1, egon wrote:
    I believe it's possible to do something simpler:
    http://play.golang.org/p/kDoOJijq3A
    Also, it's more "type-safe" at compile time and faster.
    That's brilliant! It's better than mine on all fronts.

    Thank you

    -Tobia

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nico at Dec 17, 2013 at 7:08 pm
    I don't think it is a good idea to run as many goroutines as elements.
    What was the reasoning behind that decision?


    I'm copying here an example of a similar idea. See that in this example:
    - the number of goroutines is an input
    - and the function fn takes slices to avoid "reflecting" each element.



    http://play.golang.org/p/BTUiXcRum4


    package main

    import (
      "fmt"
      "reflect"
      "sync"
    )

    func main() {
      words := []string{"Hello", "world", "here", "is", "Go"}
      lengths := make([]int, len(words))
      getLen := func(in []string, out []int) {
       for i := range in {
        out[i] = len(in[i])
       }
       fmt.Println(in, out)
      }

      Apply(getLen, words, &lengths, 2)

      fmt.Println("words =", words)
      fmt.Println("lengths =", lengths)
    }

    func Apply(fn interface{}, in interface{}, out interface{},
    numGoroutines int) {
      inVal := reflect.ValueOf(in)
      if k := inVal.Kind(); k != reflect.Array && k != reflect.Slice {
       panic("Apply: argument 'in' must be an array or a slice")
      }

      outVal := reflect.ValueOf(out).Elem()
      if k := outVal.Kind(); k != reflect.Slice {
       panic("Apply: argument 'out' must be a slice")
      }

      inLen := inVal.Len()
      if inLen > outVal.Cap() {
       panic("Apply: capacity of argument 'out' is smaller than length of
    argument 'in'")
      }
      if inLen == 0 {
       outVal.SetLen(0)
       return
      }

      fnVal := reflect.ValueOf(fn)
      if k := fnVal.Kind(); k != reflect.Func {
       panic("Apply: argument 'fn' must be a function")
      }

      inT := inVal.Type().Elem()
      outT := outVal.Type().Elem()
      if t := fnVal.Type(); t.NumIn() != 2 || t.NumOut() != 0 ||
       t.In(0).Elem() != inT || t.In(1).Elem() != outT {
       panic("Apply: type of argument 'fn' must be consistent with types of
    arguments 'in' and 'out'")
      }

      if numGoroutines <= 0 {
       panic("Apply: numGoroutines <= 0")
      }

      // grow output slice to the final length
      outVal.SetLen(inLen)

      // split work into a number of goroutines
      var wg sync.WaitGroup
      task := func(in, out reflect.Value) {
       defer wg.Done()
       fnVal.Call([]reflect.Value{in, out})
      }
      taskLen := inLen / numGoroutines

      i, j := 0, taskLen
      for j < inLen {
       wg.Add(1)
       go task(inVal.Slice(i, j), outVal.Slice(i, j))
       i, j = j, j+taskLen
      }
      wg.Add(1)
      go task(inVal.Slice(i, inLen), outVal.Slice(i, inLen))

      wg.Wait()
    }

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Tobia at Dec 17, 2013 at 11:05 pm

    On Tuesday, December 17, 2013 8:08:10 PM UTC+1, Nico wrote:
    I don't think it is a good idea to run as many goroutines as elements.
    What was the reasoning behind that decision?
    For simple cases such as those in the examples, the fastest algorithm is a
    simple for loop, with no concurrency at all, by orders of magnitude
    compared to this particular implementation of Map / Filter. There are
    benchmarks in the test file to measure how slower it is.

    The point of a fully concurrent implementation (one goroutine per element)
    is not being the most efficient, but being the most versatile. The Map and
    Filter functions could be calling external services, making network
    requests to different hosts, and so on.

    I agree that more concurrency options (at least One, NumCPU, and the
    current Max) are necessary before this thing can even remotely be called an
    actual library, but I wanted to get some feedback on the choice of API and
    on the very idea of a generic functional library for Go.

    -Tobia

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedDec 15, '13 at 4:35p
activeDec 17, '13 at 11:12p
posts7
users4
websitegolang.org

People

Translate

site design / logo © 2023 Grokbase