aboutsummaryrefslogtreecommitdiffstats
path: root/lua/nvim-lsp-installer/core/functional.lua
blob: 8b549fb656c031cb1159c43a6a1a2adefe44594e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
local functional = {}

---@generic T : string
---@param values T[]
---@return table<T, T>
function functional.enum(values)
    local result = {}
    for i = 1, #values do
        local v = values[i]
        result[v] = v
    end
    return result
end

---@generic T
---@param list T[]
---@return table<T, boolean>
function functional.set_of(list)
    local set = {}
    for i = 1, #list do
        set[list[i]] = true
    end
    return set
end

---@generic T
---@param list T[]
---@return T[]
function functional.list_reverse(list)
    local result = {}
    for i = #list, 1, -1 do
        result[#result + 1] = list[i]
    end
    return result
end

---@generic T, U
---@param fn fun(item: T): U
---@param list T[]
---@return U[]
function functional.list_map(fn, list)
    local result = {}
    for i = 1, #list do
        result[#result + 1] = fn(list[i], i)
    end
    return result
end

function functional.table_pack(...)
    return { n = select("#", ...), ... }
end

function functional.list_not_nil(...)
    local result = {}
    local args = functional.table_pack(...)
    for i = 1, args.n do
        if args[i] ~= nil then
            result[#result + 1] = args[i]
        end
    end
    return result
end

function functional.when(condition, value)
    return condition and value or nil
end

function functional.lazy_when(condition, fn)
    return condition and fn() or nil
end

function functional.coalesce(...)
    local args = functional.table_pack(...)
    for i = 1, args.n do
        local variable = args[i]
        if variable ~= nil then
            return variable
        end
    end
end

---@generic T
---@param list T[]
---@return T[] @A shallow copy of the list.
function functional.list_copy(list)
    local result = {}
    for i = 1, #list do
        result[#result + 1] = list[i]
    end
    return result
end

---@generic T
---@param predicate fun(item: T): boolean
---@param list T[]
---@return T | nil
function functional.list_find_first(predicate, list)
    local result
    for i = 1, #list do
        local entry = list[i]
        if predicate(entry) then
            return entry
        end
    end
    return result
end

---@generic T
---@param predicate fun(item: T): boolean
---@param list T[]
---@return boolean
function functional.list_any(predicate, list)
    for i = 1, #list do
        if predicate(list[i]) then
            return true
        end
    end
    return false
end

function functional.identity(a)
    return a
end

function functional.always(a)
    return function()
        return a
    end
end

---@generic T : fun(...)
---@param fn T
---@param cache_key_generator (fun(...): string | nil)|nil
---@return T
function functional.memoize(fn, cache_key_generator)
    cache_key_generator = cache_key_generator or functional.identity
    local cache = {}
    return function(...)
        local key = cache_key_generator(...)
        if not cache[key] then
            cache[key] = functional.table_pack(fn(...))
        end
        return unpack(cache[key], 1, cache[key].n)
    end
end

---@generic T
---@param fn fun(): T
---@return fun(): T
function functional.lazy(fn)
    local memoized = functional.memoize(fn, functional.always "lazyval")
    return function()
        return memoized()
    end
end

---@generic T
---@param fn fun(...): T
---@return fun(...): T
function functional.partial(fn, ...)
    local bound_args = functional.table_pack(...)
    return function(...)
        local args = functional.table_pack(...)
        local merged_args = {}
        for i = 1, bound_args.n do
            merged_args[i] = bound_args[i]
        end
        for i = 1, args.n do
            merged_args[bound_args.n + i] = args[i]
        end
        return fn(unpack(merged_args, 1, bound_args.n + args.n))
    end
end

function functional.compose(...)
    local functions = functional.table_pack(...)
    assert(functions.n > 0, "compose requires at least one function")
    return function(...)
        local result = functional.table_pack(...)
        for i = functions.n, 1, -1 do
            result = functional.table_pack(functions[i](unpack(result, 1, result.n)))
        end
        return unpack(result, 1, result.n)
    end
end

---@generic T
---@param filter_fn fun(item: T): boolean
---@return fun(list: T[]): T[]
function functional.filter(filter_fn)
    return functional.partial(vim.tbl_filter, filter_fn)
end

function functional.each(fn, list)
    for k, v in pairs(list) do
        fn(v, k)
    end
end

return functional