5

Poznaję funkcje typu pointfree i próbuję zaimplementować ten rekursywny remover w tym stylu.Bezpośrednia rekursja w JS z ramdą

działa, ale jest nie pointfree:

function removeNulls(obj) { 
    return R.ifElse(
    R.either(R.is(Array), R.is(Object)), 
    R.pipe(
     R.filter(R.pipe(R.isNil, R.not)), 
     R.map(removeNulls) 
    ), 
    R.identity 
)(obj) 
} 

module.exports = removeNulls 

Poniżej moja nie działa próba na to:

const removeNulls = R.ifElse(
    R.either(R.is(Array), R.is(Object)), 
    R.pipe(
    R.filter(R.pipe(R.isNil, R.not)), 
    // throws `ReferenceError: removeNulls is not defined` 
    R.map(removeNulls) 
), 
    R.identity 
) 
+1

Nie możesz, ponieważ JavaScript nie stanowią drogę do leniwie deklaruj argumenty. Możesz mieć szczęście używając kombinatora 'Y', ale stanie się to naprawdę brzydkie. – Bergi

+0

@Bergi Dzięki za cynk, zostawię go tak, jak jest. Chciałbym dowiedzieć się więcej o użyciu kombinatora Y, jeśli tylko do przyszłego użytku. Wygląda na to, że [ramda nie ma kombinatora 'Y'] (https://gist.github.com/Avaq/1f0636ec5c8d6aed2e45), ale nie wiem, dokąd się udać. Trochę trudno jest google dla ... –

+0

@Bergi jest poprawny, nie można tego zrobić ze stałą ... ale możesz to zrobić, jeśli oddzielisz akcję od zastosowania: const filterNotNull = filter (pipe (isNil nie)) const recurseAction = działania => ifElse ( albo (jest (array) jest (Object)), rura ( działania, mapę (działanie) ) tożsamość ) –

Odpowiedz

2

brak Javascript w lenistwa jest podwójny zabójca tutaj: ty nie można wywołać go, gdy jest const, ponieważ znajdujesz się w tym samym zakresie i próbujesz rozwiązać resolveNulls w jego definicji.

Ponadto, nie można po prostu mapie (recurseAction (działanie)), ponieważ sama definicja będzie dmuchać stos, więc trzeba zawinąć go w innym zakresie, aby to zrobić:

const {ifElse, always, tap, apply, either, is, isNil, not, pipe, filter, map, identity} = require('ramda') 

const filterNotNull = filter(pipe(isNil, not)) 
const log = tap(console.log) 

const recurseAction = 
    action => 
    ifElse(
     either(is(Array), is(Object)), 
     pipe(
     action, 
     map(a => recurseAction(action)(a)) 
    ), 
     identity 
    ) 

const removeNulls = recurseAction(filterNotNull) 

const a = { 
    a: null, 
    b: "blah", 
    c: 2, 
    d: undefined, 
    e: { 
    meow: null, 
    blah: undefined, 
    jim: 'bob' 
    } 
} 

const b = removeNulls(a) 
console.log(b) 
6

szczęście JavaScript ma zasoby, aby poradzić sobie z brakiem lenistwa. Tak więc, możliwe jest zadeklarowanie rekurencyjnego, bezwzrokowego rozwiązania za pomocą funkcji lambda w następujący sposób: a => f(a). Wystarczy wymienić R.map(removeNull) na R.map(a =>removeNull(a)).

const removeNulls = R.ifElse(
    R.either(R.is(Array), R.is(Object)), 
    R.pipe(
     R.filter(R.pipe(R.isNil, R.not)), 
     R.map(a => removeNulls(a)) 
    ), 
    R.identity 
) 

W twoim przypadku, to polecam użyć R.reject który jest oposite do R.filter. Ponieważ są negując orzecznik, R.filter(R.pipe(R.isNil, R.not)) jest równa R.reject(R.isNil)

const removeNulls = R.ifElse(
    R.either(R.is(Array), R.is(Object)), 
    R.pipe(
     R.reject(R.isNil), 
     R.map(a => removeNulls(a)) 
    ), 
    R.identity 
) 

Wreszcie, funkcja ta ma następującą strukturę ifElse(predicate, whenTrue, identity) która jest równa when(predicate, whenTrue)

const removeNulls = R.when(
    R.either(R.is(Array), R.is(Object)), 
    R.pipe(
     R.reject(R.isNil), 
     R.map(a => removeNulls(a)) 
    ) 
) 
Powiązane problemy