Святилище Js и определение контравариантного функтора - PullRequest
0 голосов
/ 09 июня 2018

Я пробую это с нуля, узнавая о Контравариантах и ​​более глубоких знаниях Святилища.Код «работает», но опять же у меня нет точно правильных типов.

Вот Контравариант

const {contramap: contramapFl, extract } = require('fantasy-land');
const getInstance = (self, constructor) =>
    (self instanceof constructor) ?
        self :
        Object.create(constructor.prototype) ;
// Contra a ~> g: a -> ?
const Contra = function(g){
    const self = getInstance(this, Contra)

    // :: F a ~> b -> a -> F b [ b -> a -> ? ]
    self[contramapFl] = f => Contra( x => g(f(x)) )
    self[extract] = g
    self['@@type'] =  'fs-javascript/contra'

    return Object.freeze(self)
}
// UPDATE adding type to constructor
Contra['@@type'] =  'fs-javascript/contra'

И моя попытка получить правильные типы

const $ = require('sanctuary-def');
const type = require('sanctuary-type-identifiers');
const Z = require('sanctuary-type-classes') ;

const isContra = x => type (x) === 'fs-javascript/contra'

const ContraType = $.UnaryType(
    'fs-javascript/contra',
    'http://example.com/fs-javascript#Contra',
    isContra,
    x => [x[extract]])($.Unknown)

Тогда мой тест

const {create, env} = require('sanctuary');
const {contramap} = create({checkTypes: true, env: env.concat(ContraType) });

const isEven = Contra(x => x % 2 === 0) ;
console.log(Z.Contravariant.test(isEven)) // => true

const isLengthEvenContra = contramap(y => y.length, isEven)
const isStringLengthEven = isLengthEvenContra[extract]

console.log(isStringLengthEven("asw")) //=> ERROR
TypeError: Type-variable constraint violation

contramap :: Contravariant f => (b -> a) -> f a -> f b
                                              ^
                                              1

1)  "fs-javascript/contra" :: String
    f => Contra( x => g(f(x)) ) :: Function, (c -> d)
    x => x % 2 === 0 :: Function, (c -> d)

Since there is no type of which all the above values are members, the type-variable constraint has been violated.

Если я отключу проверку типов, то она будет работать, как и ожидалось, поэтому логически она выглядит правильно сшитой.Я определил свою собственную версию contramap

const def = $.create({ checkTypes: true, env: $.env.concat(ContraType) });

const contramap2 =
    def('contramap2', {}, [$.Unknown, ContraType, ContraType],
        (f, x) => {
            const z = x[contramapFl](f)
            return z
        }
    )

. Затем я перезапустил тест:

const isEven = Contra(x => x % 2 === 0) ;
console.log(Z.Contravariant.test(isEven)) // => true

const isLengthEvenContra = contramap2(y => y.length, isEven)
const isStringLengthEven = isLengthEvenContra[extract]

console.log(isStringLengthEven("asw")) //=> false

. Таким образом, я выдержал дискуссию о том, является ли контравариантный функтор лучшим подходом к этой проблеме (обучениеупражнение), вопрос в том, как при определении собственной реализации контраварианта я могу использовать функцию контракарты святилища с включенной проверкой типов .


после обновления, добавив код:

Contra['@@type'] =  'fs-javascript/contra'

изменил ошибку на:

TypeError: Type-variable constraint violation

contramap :: Contravariant f => (b -> a) -> f a -> f b
                                      ^       ^
                                      1       2

1)  3 :: Number, FiniteNumber, NonZeroFiniteNumber, Integer, NonNegativeInteger, ValidNumber

2)  x => x % 2 === 0 :: Function, (c -> d)

Since there is no type of which all the above values are members, the type-variable constraint has been violated.
// Contra (Integer -> Boolean)
const isEven = Contra(x => x % 2 === 0) ;
// String -> Integer
const strLength = y => y.length
// I Think: Contra (String -> (Integer -> Boolean))
const isLengthEvenContra = contramap(strLength, isEven)
// (String -> (Integer -> Boolean))
const isStringLengthEven = isLengthEvenContra[extract]

Мое пониманиеиз контравариантного функтора заключалось в том, что он предварительно составлял функцию внутри него, причем функция передавалась через contramap.Таким образом, если контравариант содержит функцию f и равен contramap с g, он возвращает новое контравариантное обертывание функтора x = g(f(x)) Не понял ли я это (тоже)

Ответы [ 2 ]

0 голосов
/ 13 июня 2018

Вот шаблон для определения пользовательского типа и включения его в среду Sanctuary:

'use strict';

const {create, env} = require ('sanctuary');
const $             = require ('sanctuary-def');
const type          = require ('sanctuary-type-identifiers');

//    FooType :: Type -> Type
const FooType = $.UnaryType
  ('my-package/Foo')
  ('https://my-package.org/Foo')
  (x => type (x) === 'my-package/Foo@1')
  (foo => []);

//    foo :: Foo
const foo = {
  'constructor': {'@@type': 'my-package/Foo@1'},
  'fantasy-land/contramap': function(f) {
    throw new Error ('Not implemented');
  },
};

const S = create ({
  checkTypes: true,
  env: env.concat ([FooType ($.Unknown)]),
});

S.I (foo);
// => foo

S.contramap (S.I) (foo);
// ! Error: Not implemented
0 голосов
/ 11 июня 2018

Вы сочиняете функции.Sanctuary определяет fantasy-land/map и fantasy-land/contramap для Function a b, поэтому нет необходимости в типе упаковки Contra.

> S.map (S.even) (s => s.length) ('Sanctuary')
false

> S.contramap (s => s.length) (S.even) ('Sanctuary')
false
...