zl程序教程

您现在的位置是:首页 >  其他

当前栏目

[Functional Programming] Function modelling -- 7. contramap & Endo execrises

amp -- Function Programming functional
2023-09-14 08:59:14 时间
// Definition

const Endo = run => ({
  run,
  concat: other => Endo(x => other.run(run(x)))
});

Endo.empty = () => Endo(x => x);

// Ex1:
// =========================

const classToClassName = html => html.replace(/class\=/gi, "className=");

const updateStyleTag = html => html.replace(/style="(.*)"/gi, "style={{$1}}");

const htmlFor = html => html.replace(/for=/gi, "htmlFor=");

//const ex1 = html =>
//    htmlFor(updateStyleTag(classToClassName(html))) //rewrite using Endo
// Can also use List foldMap

// Solution1
// const ex1 = html => List.of(htmlFor, updateStyleTag, classToClassName).foldMap(Endo, Endo.empty()).run(html)
// Solution 2
// const ex2 = html => [htmlFor, updateStyleTag, classToClassName].reduce((acc, curr) => acc.concat(Endo(curr)), Endo.empty()).run(html)
// Solution 3
const ex1 = html =>
  Endo(htmlFor)
    .concat(Endo(updateStyleTag))
    .concat(Endo(classToClassName))
    .run(html);

QUnit.test("Ex1", assert => {
  const template = `
        <div class="awesome" style="border: 1px solid red">
            <label for="name">Enter your name: </label>
            <input type="text" id="name" />
        </div>
    `;
  const expected = `
        <div className="awesome" style={{border: 1px solid red}}>
            <label htmlFor="name">Enter your name: </label>
            <input type="text" id="name" />
        </div>
    `;

  assert.deepEqual(expected, ex1(template));
});

// Ex2: model a predicate function :: a -> Bool and give it contramap() and concat(). i.e. make the test work
// =========================
const Pred = run => ({
  run,
  contramap(f) {
    return Pred(x => run(f(x)));
  },
  concat(otherM) {
    return Pred(x => run(x) && otherM.run(x));
  }
}); // todo

QUnit.test("Ex2: pred", assert => {
  const p = Pred(x => x > 4)
    .contramap(x => x.length)
    .concat(Pred(x => x.startsWith("s")));
  const result = ["scary", "sally", "sipped", "the", "soup"].filter(p.run);
  assert.deepEqual(result, ["scary", "sally", "sipped"]);
});

// Ex3:
// =========================
const extension = file => file.name.split(".")[1];

const matchesAny = regex => str => str.match(new RegExp(regex, "ig"));

const matchesAnyP = pattern => Pred(matchesAny(pattern)); // Pred(str => Bool)

// TODO: rewrite using matchesAnyP. Take advantage of contramap and concat
//const ex3 = file =>
//    matchesAny('txt|md')(extension(file)) && matchesAny('functional')(file.contents)
const ex3 = file =>
  matchesAnyP("txt|md")
    .contramap(extension)
    .concat(matchesAnyP("functional").contramap(f => f.contents))
    .run(file);

QUnit.test("Ex3", assert => {
  const files = [
    { name: "blah.dll", contents: "2|38lx8d7ap1,3rjasd8uwenDzvlxcvkc" },
    {
      name: "intro.txt",
      contents: "Welcome to the functional programming class"
    },
    { name: "lesson.md", contents: "We will learn about monoids!" },
    {
      name: "outro.txt",
      contents:
        "Functional programming is a passing fad which you can safely ignore"
    }
  ];

  assert.deepEqual([files[1], files[3]], files.filter(ex3));
});