Монадическая композиция упражнение неправильное - PullRequest
0 голосов
/ 19 мая 2018

Фон

Я читаю Адекватное руководство по функциональному программированию и выполняю все упражнения.Я нахожусь в главе 9, Лук Monadic , но я борюсь с упражнениями.

Упражнение 1

С учетом объекта User, описанного ниже, используйте safeProp и map/join или chain, чтобы безопасно получить название улицы при предоставлении пользователю:

// safeProp :: String -> Object -> Maybe a
const safeProp = curry((p, obj) => compose(Maybe.of, prop(p))(obj));

const user = {  
  id: 1,  
  name: 'Albert',  
  address: {  
    street: {  
      number: 22,  
      name: 'Walnut St',  
    },  
  },  
};

Решение 1

// getStreetName :: User -> Maybe String
const getStreetName = compose(
    chain( safeProp( "name" ) ),
    chain( safeProp( "street" ) ),
    safeProp( "address" )    
);

Это было легко.safeProp возвращает Возможно Монаду.Таким образом, при составлении safeProp нам нужно использовать chain (он же flatMap), чтобы продолжить, в противном случае вместо Maybe.of("value") мы получим Maybe.of( Maybe.of("value") ).

Правило выведено : если вы хотите составить функцию A и функцию B, и оба возвращают монады, используйте chain!

Упражнение 2

Учитывая следующие функции,используйте getFile, чтобы получить путь к файлу, удалить каталог и оставить только базовое имя, а затем просто зарегистрировать его.Подсказка: вы можете использовать split и last для получения базового имени из пути к файлу.

// getFile :: () -> IO String
const getFile = () => IO.of('/home/mostly-adequate/ch9.md');

// pureLog :: String -> IO ()
const pureLog = str => new IO(() => console.log(str));

Решение 2

const getBaseName = compose( last, split("/") );

const logFilename = compose(
    chain( pureLog ),
    map( getBaseName ),
    getFile
);

Это немногоболее хитрый, но мне тоже это удалось.

Итак, getFile возвращает IO Monad.Но getBaseMap возвращает только строку.Итак, у меня есть функция A, которая возвращает монаду, и функция B, которая возвращает примитивный тип.Я не могу составить их, используя chain, потому что функция B не имеет ничего, что нужно сгладить.Это означает, что мне нужно map, чтобы составить А с В!

Еще одно правило!

Теперь мне нужно составить B с pureLog (C).После наложения карты на B, она вернет IO Monad с преобразованным значением.Давайте назовем это MB.Учитывая, что мне нужно составить MB с C (который возвращает монаду), я не могу применить правило 1 и просто использовать chain.

Фу!

Давайте перейдем к последнему!

Упражнение 3:

С учетом следующих функций используйте validateEmail, addToMailingList и emailBlast, чтобы создать функцию, которая добавляет новое электронное письмо в список рассылки, если он действителен, изатем уведомить весь список.

// validateEmail :: Email -> Either String Email // addToMailingList :: Email -> IO ([Email]) // emailBlast :: [Email] -> IO ()

Решение 3?

Я понятия не имею, как сделать это ....

Это то, что я сделал до сих пор:

// joinMailingList :: Email -> Either String (IO ())
const joinMailingList = compose(
    chain( emailBlast ),
    chain( addToMailingList ),
    validateEmail    
);

Но это не так.Я получаю следующую ошибку:

Функция имеет недопустимый тип;подсказка: joinMailingList должен возвращать любую строку (IO ())

Вопросы:

  1. Как это исправить?Может кто-нибудь объяснить мне, что не так?
  2. Должен ли я вывести дополнительные правила из предыдущих упражнений (я здесь пропускаю какое-то правило компоновки)?

1 Ответ

0 голосов
/ 19 мая 2018
// validateEmail :: Email -> Either String Email
// addToMailingList :: Email -> IO([Email])
// emailBlast :: [Email] -> IO ()

означает, что вы не можете использовать Either.chain, вам нужно map вместо Either String, что первая функция в композиции (validateEmail) возвращается.Как вы знаете, « я не могу составить их, используя цепочку, потому что функция B не имеет ничего, что нужно сглаживать. ».

Обратите также внимание, что у нас есть two здесь монады, две разные монады: Either и IO.chain не работает с любой монадой, он работает только с одинаковым монадическим типом в обоих своих аргументах.Каждая монада (т.е. каждый тип, являющийся монадой) имеет свой собственный метод chain.Использование одной функции chain - это просто абстракция, которая использует полиморфизм времени выполнения (или полиморфизм времени компиляции, если в языке есть поддерживающий это компилятор).Так что нам понадобится

function joinMailingList(email) {
    return Either.map(validateEmail(email), addAndBlast)
}
function addAndBlast(email) {
    return IO.chain(addToMailingList(email), emailBlast)
}
...