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