Монадическая композиция упражнение неправильное

Фон

Я читаю " Достаточно адекватное руководство по функциональному программированию" и делаю все упражнения. Я нахожусь в главе 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 -> E либо 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 ответ

Решение
// validateEmail :: Email -> Either String Email
// addToMailingList :: Email -> IO([Email])
// emailBlast :: [Email] -> IO ()

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

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

function joinMailingList(email) {
    return Either.map(validateEmail(email), addAndBlast)
}
function addAndBlast(email) {
    return IO.chain(addToMailingList(email), emailBlast)
}
Другие вопросы по тегам