Фон
Я читаю Адекватное руководство по функциональному программированию и выполняю все упражнения.Я нахожусь в главе 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 ())
Вопросы:
- Как это исправить?Может кто-нибудь объяснить мне, что не так?
- Должен ли я вывести дополнительные правила из предыдущих упражнений (я здесь пропускаю какое-то правило компоновки)?