GithubHelp home page GithubHelp logo

yonaba / moses Goto Github PK

View Code? Open in Web Editor NEW
624.0 30.0 104.0 1.41 MB

Utility library for functional programming in Lua

Home Page: http://yonaba.github.io/Moses

License: MIT License

Lua 100.00%
lua underscore functional-programming table functional array object collection

moses's Introduction

Build Status Latest Stable License Lua

A Lua utility-belt library for functional programming.

Examples

How can I get the sum of all integers between 1 and 100 ?

local sum = M.sum(M.range(100))
print(sum) -- 5050

Say I am looking for the length of the longest word in some array ?

local words = {'some','words','of','different','lengths'}
print(M.max(words, M.op.length)) -- 9 letters

What is the sum of all fibonacci numbers for n below or equal 25 ?

local function fib(n) return n < 2 and n or fib(n - 1) + fib(n - 2) end
local fibsum = M.sum(M.map(M.range(25), fib))
print(fibsum) -- 196417

Or let us do the same, object-oriented style with chaining :

local function fib(n) return n < 2 and n or fib(n - 1) + fib(n - 2) end
local fibsum = M.chain(M.range(25)):map(fib):sum():value()
print(fibsum) -- 196417

Or even shorter :

local fibsum = M(M.range(25)):map(fib):sum():value()
print(fibsum) -- 196417

Feel free to download and try it on your own!

Download

Archive

Bash

git clone git://github.com/Yonaba/Moses.git

LuaRocks

luarocks install moses

MoonRocks

moonrocks install moses

Usage

local M = require "moses"

Note: the full source moses.lua is quite heavy (~92 kiB, 3115 LOC). You can alternatively use the minified version (~35 kiB, 561 LOC).

Tutorial

Find a complete set of code examples in tutorial.md.

Documentation

Credits and Acknowledgement

Specification

Run spec tests from Lua using busted with the following command from the root folder:

busted

License

This work is under MIT-LICENSE
Copyright (c) 2012-2018 Roland Yonaba.
See LICENSE.

moses's People

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

moses's Issues

Bug in Intersect, Questions about Difference and Union

Hi!

I'm playing with Penlight and Moses and came across some odd behaviour. I read in two tab separated files using the penlight data module and then run his data.select method that returns an iterator function to the list (script at the bottom).

First, I get an error when I run moses.intersection:

C:\Program Files (x86)\WinLua\Lua\5.3\bin\lua.exe: attempt to index a function value
stack traceback:
        [C]: in for iterator 'for iterator'
        .\moses.lua:1064: in function <.\moses.lua:1061>
        (...tail calls...)
        .\compare-projects.lua:33: in main chunk
        [C]: in ?

Next I get different behaviour between diff and union. When I run moses.diff, I get back a function. but when I run union, I get back a table that contains a function. Not sure what to make of that?

Anyway, thanks for the great library that makes a someone with grade 11 math feel smart!

The data I am using is here: https://pastebin.com/FBuMcxZe and here https://pastebin.com/swZVC5YB

require('pl')
local m = require('moses')

utils.printf("%s\n","That feels better")
local lfw = data.read('lfw_modules.tab')
local lp = data.read('luaplus_modules.tab')

--intersection to get all  matches
-- Union to get duplicate free list
-- difference -- gets the non matchs
local function write(filename, func)
local wt = {}
for i in func do
	wt[#wt+1] = i 
end
file.write(filename, pretty.write(wt))

end

local W1 = lfw:select('NAME')
local P1 = lp:select('NAME')

local diff = m.difference(W1,P1)
print(type(diff))
local union = m.union(W1,P1)
print(type(union))
print(pretty.write(union))

write('wp_diff.txt', m.difference(W1,P1)) --returns a function
file.write('wp_union.txt', pretty.write(union))
-- This blows up
--write('wp_intersect.txt', m.intersection(W1,P1))

Using moses without require

Hi there,

I was hoping you could instruct me how to use moses without require.

I would like to use it in a Redis script, so I have to concatenate my script and any additional scripts into a single file, without using additional statements. Also I'd like to use it in repl.it and there is no way to use require there.

TIA
Jan

Interview With Moses Author?

Hi Roland!

There is a new Lua forum called... luaforum.com (!) and we have created a section about LuaRocks. The idea is to get LuaRocks authors to write about their libraries. I have had a great deal of success with Moses at various times and wanted to invite you to do an "interview" that will be posted on the Forum?

The idea (at the moment) is to write some questions and you could fill in the answers (I'd be happy doing a skype interview instead if you were interested)? We would also do a mock project to show people how Moses is used. Moses is a little different because you have so much documentation, which makes the mock project a little less necessary. I none the less think it would be a great idea.

Thoughts?
Cheers,
Russ

M.compose()

I did some tests with M.compose() and a custom implementation:

function M.compose(...)
  local fn = M.reverse {...}
  local function exec(i, ...)
    if i == #fn then return fn[i](...) end
    return exec(i+1, fn[i](...))
  end
  return function(...) return exec(1, ...) end
end

maybe I'm doing something wrong but this custom function, which uses recursivity, is much faster than the original implementation. FYI, this function passes all the tests.

Feature request: findWhere(t, f)

Extend findWhere to accept a function as it's second argument instead of a table.

For example, find the first even number in a table:

t = {1, 2, 3}
result = __.findWhere(t, function(value)
    return value % 2 == 0
end)
print(result) --> 2

powerset does not generate a power set

Despite its name, powerset does not actually create a power set. For example, the documentation states when given the set {1,2,3}, returns {{1},{2},{3},{1,2},{2,3},{1,2,3}} however the power set of {1,2,3} is actually {{},{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}}. Specifically {} and {1,3} are missing in this case.

sample() fails when array contains middleclass classes

The sample(array, numSamples) function seems to be sensitive to datatypes allowed in the array argument, and fails to return any array elements when an array contains middleclass class instances.

Test using Busted:

local class = require 'middleclass'
local moses = require 'moses'

describe('moses sample()', function()

  it('works when array contains Vector classes', function()

    local DenseVector = class('DenseVector')
    function DenseVector:initialize(data)
      self.data = data
    end

    local vector1 = DenseVector:new({1,2,3})
    local vector2 = DenseVector:new({4,5,6})

    local sample = moses.sample({vector1, vector2}, 1)
    assert.equal(1, #sample) -- <== fails because #sample is 0
    assert.is_true(sample[1]:isInstanceOf(DenseVector)) -- <== never runs
  end)

end)

behavior : _.isNumber() _.isInteger()

values with [ "" ], i.e., '0', '1.1', ... are not valid

sugest:
_maybe a flag can 'help' with this .isNumber( value, [true] ) can force a number/integer convert/cast.

$ cat test.moses.isnumber.lua
_ = dofile('moses.lua')
tbl = { 1, 1.99, .99, -1, 0, '', '0', '1', '1.1', '-1', false, nil }
_.eachi( tbl, function(i, v) print( i, tostring(v), _.isNumber(v), _.isInteger(v) ) end)

--- output
1 1 true true
2 1.99 true false
3 0.99 true false
4 -1 true true
5 0 true true
6 false false
7 0 false false
8 1 false false
9 1.1 false false
10 -1 false false
11 false false false

Many functions not chainable because of f(i,k) 1st arg

In lodash/underscore, most functions are chainable because function callbacks are passed a value. That allows constructs such as this in JavaScript:

local positives = _.map({1,-2,3,-4}, math.abs)

Such constructs don't work in Moses because some (but not all) functions are passed in index argument before a key argument. This is essential for efficient Lua, but undesirable when function chaining is desired. Here's what you currently have to do in Moses:

positives = moses.map({1,-2,3,-4}, function(i,v) return math.abs(v) end)

And because of this, Moses has great function chaining functions like pipe() and compose() that it seems like I never have a chance to use.

Off the top of my head, one idea is to create a new method with an "i" suffix when a callback function will be passed an index before a key. Eg:

positives = moses.mapi({1,-2,3,-4}, function(i,v) return math.abs(v) end)
-- or
positives = moses.map({1,-2,3,-4}, math.abs) 

groupBy does not pass additional arguments

groupBy(t, iter, ...) is supposed to pass extra arguments to iter but it actually does not:

local __ = require "moses"
__.groupBy({"foo"}, function(i, s1, s2) return s1..s2 end, "bar")

Expected result: groupBy returns {["foobar"] = {"foo"}}
Actual result:

attempt to concatenate local 's2' (a nil value)
stack traceback:
    testcase.lua:2: in function 'iter'
    ./moses.lua:470: in function 'f'
    ./moses.lua:82: in function 'each'
    ./moses.lua:469: in function <./moses.lua:466>
    (...tail calls...)
    testcase.lua:2: in main chunk
    [C]: in ?

_.size behavior

Hi, this behavir is expected on: string and boolean values?

moses-size.lua
print( _VERSION );
print('no args', _.size(), 'nil', _.size(nil), 'false', _.size(false), 'true', _.size(true), 'string empty', _.size(''), '{}', _.size({}), '{{},{}}', _.size( { {}, {} }) );

lua moses-size.lua
Lua 5.1
no args 0 nil 0 false 1 true 1 string empty 1 {} 0 {{},{}} 2

Feature Request: takeWhile, dropWhile

While you're adding features, could you add these too (from Haskell):

takeWhile: alias to selectWhile
dropWhile: as the name suggests, drop elements of array till the condition is met

Very useful lib btw :)

Feature request: unpack()

The global unpack() was deprecated in Lua 5.3, and moved to the table module. Therefore, lots of Lua programs, including Moses, contain a line like this:

local unpack = table.unpack or unpack

This makes it useful to everyone. It'd be nice to not have such lines in my programs, and instead call Moses:

local x,y = moses.unpack(array)

Use of underscore ("_") and "M" from Lua Style Guide

The Lua coding standard designates the underscore (_) as the standard global variable to use in place of an unused variable. Moses uses it as the current-module variable, which is typically represented by a local variable M.

Recommendation:

  • Replace _ with M in sources; then
  • replace __ with _ in sources

Static analysis programs such as luacheck make use of the Lua Style Guide conventions.

Last is different to Rest

We found last recently changed, and it is not aliased to rest. Which version of underscore are you mapping it to? From what I see, Last by counting last n entries and rest is the starting index, so they are different.

By the way, we have been using your script to work in our project, thanks for the effort.

bug or expected behavior --- _.findWhere x _.select

'the code explict all'


--- src code

-- http://www.gammon.com.au/files/smaug/lua/tprint.lua
-- https://github.com/Yonaba/Moses

_ = require('moses_min')
tprint = require('tprint')

local m = {
{id=1, v='value-1'},
{id=2, v='value-2'},
{id=3, v='value-3'},
{id=1, v='value-1-1'},
{id=1, v='value-1-1'}
};

id = 1;

-- returns the first
x = _.findWhere(m, {id=id} );
tprint(x)

-- return all
x = _.select(m, function(k, v)
return (v.id == id);
end);
tprint(x);


--- output

$ lua findWhere.lua

findWhere
"id"=1
"v"="value-1"

select
1 :
"id"=1
"v"="value-1"
2 :
"id"=1
"v"="value-1-1"
3 :
"id"=1
"v"="value-1-1"

uid() alias refers to non-existent uniqueid()

uid() should be an alias for uniqueId(), not uniqueid().

moses = require 'moses'
print(moses.uniqueId())
0
print(moses.uniqueId())
1
print(moses.uniqueId())
2

print(moses.uid())
stdin:1: attempt to call field 'uid' (a nil value)

Feature request: mapi()

I do miss a mapi() function, it would work like map() but use ipairs() instead of pairs().
Motivation: That are some tables that we are sure that they are just an array and ipairs is much faster on LuaJIT.

Don't treat io or os modules as mandatory (redis compatibility)

Amalgamated Lua scripts that inline Moses are unable to be loaded by Redis, due to its lack of support for the optional io and os modules, combined with its strict validator which ensures no Lua code is referencing a global that was not implicitly assigned.

Here's an example of a typical error message:

$ redis-cli --eval SparkPi-with-dependencies.lua 
(error) ERR Error running script (call to f_9ee542b8c203fc67d9dd0f620ee442e5ea6ecd9e): @user_script:36: user_script:36: attempt to index upvalue 'os' (a nil value)

Lines in Moses like this:

local clock = os.clock

Might need to change to something like this:

local clock = os and os.clock or nil

Please make moses available for 5.4

According to the luarock webisite, the latest moses library is only available for lua version < 5.4. When I try to install moses for lua 5.4, I got the version 1.6 by default, which is pretty old.

Version 2.1.0-1 of moses was uploaded 2 years ago. For lua >= 5.1, < 5.4
Is there any reason that Moses is not working for 5.4?

working with matrix

Hi. I'm new on function programming-like.

moses works fine with array, i.e.
tbl = {id=1, value=12.23};

but with i can work
tbl = {
{id=1, value=12.23},
{id=2, value=32.33
[...]
};

i have to select? or how can process/find/sort using this data movel

sugesstion: add functions to de/serialize using files

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.