These are chat archives for ramda/ramda

9th
Jul 2015
you in here?
Kevin Wallace
@kedashoe
Jul 09 2015 06:19
I was going to comment on the.. nestedness of that function and normally would not have done it point-free, but that was the style of the other functions so i just went with it
would not be surprised if there if a much nicer point-free solution :)
David Chambers
@davidchambers
Jul 09 2015 06:19
Yes, I’m here.
Let’s see what we can do here.
So the input is a list of zero or more strings.
Each of which contains one or more comma-separated words.
Kevin Wallace
@kedashoe
Jul 09 2015 06:20
yep
David Chambers
@davidchambers
Jul 09 2015 06:21
R.chain(R.split(/\s*,\s*/)) is all we need, I think. :)
Oh, we also need to remove the prefixes, so:
R.pipe(R.chain(R.split(/\s*,\s*/)), R.map(R.drop(R.length('R.'))))
Kevin Wallace
@kedashoe
Jul 09 2015 06:24
pretty much
ya
and there is already a helper for that last part
David Chambers
@davidchambers
Jul 09 2015 06:25
Nice one.
Kevin Wallace
@kedashoe
Jul 09 2015 06:26
k so i've got
var simplifySee = R.pipe(
  R.chain(R.split(/\s*,\s*/)),
  R.map(unprefix)
);
David Chambers
@davidchambers
Jul 09 2015 06:26
Nice!!
Kevin Wallace
@kedashoe
Jul 09 2015 06:27
thanks :) will update PR
David Chambers
@davidchambers
Jul 09 2015 06:32

Now I wonder whether we should just write:

see: R.map(unprefix, R.chain(R.split(/\s*,\s*/), see)),

This would avoid R.pipe altogether. :)

It’s up to you.
If you decide to name the function, though, it would be good to add a type signature. That’s the main reason to define top-level functions, in my view.
Kevin Wallace
@kedashoe
Jul 09 2015 06:35
I think the sig is pretty uninteresting in this case? [String] -> [String] right? maybe should just inline like you suggest then?
David Chambers
@davidchambers
Jul 09 2015 06:36
It’s up to you. If you want to keep the top-level declaration, I’d like to see [String] -> [String]. It saves readers from having to do their own type inference. ;)
Kevin Wallace
@kedashoe
Jul 09 2015 06:39
sig added
David Chambers
@davidchambers
Jul 09 2015 06:40
LGTM!
James Forbes
@JAForbes
Jul 09 2015 06:51

var extractArgumentNames = function(){
  var fnStr = request.toString()
  var bodyI = fnStr.indexOf("{")
  var defn = request.toString().substring(0, bodyI)
  var args = defn.substring(
    defn.indexOf("(")+ 1,
    defn.lastIndexOf(")")
  )
  .replace(/\s/g, "").split(",")
  return args;
}

/*
  Converts a given function into a curried keyword function.  It will not invoke until it has received all 
  of its required arguments.

  The list of required arguments is determined by analysing the function body and the defaults hash.
  If there is an argument present in the body but not in the defaults, it is assumed to be required.
*/
var kwargs = function(func, defaults){
  var arg_names = extractArgumentNames(func);

  var received_values = [];


  var required_args = Object.keys(defaults).filter(function(arg_name){
    return typeof defaults[arg_name] === "undefined";
  })

  function work(received_values, required_received, options){
    required_received = required_received || 0
    received_values = received_values && received_values.slice() || []

    var input_args = Object.keys(options);

    //process latest args
    input_args.forEach(function(arg){
      var arg_position = arg_names.indexOf(arg)
      var required_position = required_args.indexOf(arg)

      //ignore invalid arguments --could throw an error I guess?
      if( arg_position > -1){
        var current_value = received_values[arg_position]

        //is this argument required?
        if( required_position > -1 ){
          //check if we are overwriting an existing received arg       
          if( typeof current_value === "undefined" ){
            required_received++
          }
        }

        //store the value for application later
        received_values[arg_position] = options[arg]


      }

    })

    // we can only apply the function if we've received all the required args
    if(required_received >= required_args.length ){
      var final_args = arg_names.map(function(arg_name, i){
        var value = received_values[i]
        return typeof value === "undefined" ? defaults[arg_name] : value
      })
      return func.apply(null, final_args);
    } else {
      return work.bind(null, received_values, required_received)
    }
  }

  //first use
  return work.bind(null, null, null);
}

//usage

//example function
function request( protocol, port, url ){
  return protocol + "://" + url + (port == 80 ? "" : ":"+port)
}

//creating keyword argument curried function
var kRequest = kwargs(request, {
  port: 80,
  protocol: "http",
  url: undefined
})

//tests


;([
  kRequest
    ({})
    ({})
    ({url: "google.com"}) == "http://google.com"

  ,

  kRequest
    ({ port: 3000 })
    ({url: "localhost"})  == "http://localhost:3000",

  kRequest
    ({ port: 3000 })
    ({ protocol: "https", port: 3001 })
    ({ url: "github.com"}) == "https://github.com:3001"

]).every( function(val){ return val} ) && "All tests passed"
James Forbes
@JAForbes
Jul 09 2015 07:11
Found a couple of bugs. But pretty fun
James Forbes
@JAForbes
Jul 09 2015 07:27
Issue: ramda/ramda#1258
Asaf
@asaf-romano
Jul 09 2015 13:41
some comments there.
nomosyn
@nomosyn
Jul 09 2015 16:27
Hi! Just wondering... Did someone try to add multidimensional arrays operators like those in J or K ? Seems like a natural fit to me because of the point-free style of Rambda. To be fair, I would like it :-)
David Chambers
@davidchambers
Jul 09 2015 17:56
Thanks for the comments, @scott-christopher! I’m very happy with the changes you suggested.
Scott Sauyet
@CrossEye
Jul 09 2015 20:55
@nomosyn: no one's tried that to my knowledge. Why do you see it as a good fit? Can it be explained to someone who doesn't know anything about J or K except that their terse syntax looks like line noise? :smile:
@nomosyn:
A lot of the points-free is incidental. It comes for free with the currying, which itself is there to support easy composition.
nomosyn
@nomosyn
Jul 09 2015 21:15
Here are the explanations: section 5.2 of this wonderful article. Here's an approximation of how it could be implemented (no need for the extra tersness that could be a bit harsh for some eyes). The way ramda uses currying is why I see a natural fit (incidental point-free + composition) which makes the whole point of ramda for me... adding the above primitives would make it even more relevant (to me at least) !
David Chambers
@davidchambers
Jul 09 2015 22:08

@asaf-romano:

On a side note, I think R.toString is using .constructor.name

Why do you say that? It just does .toString() to get the string representation of a function (source).

Scott Christopher
@scott-christopher
Jul 09 2015 23:53
@davidchambers Happy to have a look.