Я думал, что одно из мест поиска, когда разрешающим требованием является оператор node_modules текущего исполняемого процесса?
blockquote>Нет;
require
выполняет поиск вnode_modules
в том же каталоге, что и файл, содержащий запускrequire
и всех его родителей. Таким образом,require
в/path/to/dir2/moduleA.js
выполняет поиск:
/path/to/dir2/node_modules/
/path/to/node_modules/
/path/node_modules/
/node_modules/
Правильный способ сделать это в
/path/to/dir2
, еслиdir2
является полным модулем:sudo npm link
Затем снова в
dir1
:npm link dir2
И правильно укажите свои зависимости для каждого из них.
Здесь вы можете использовать функцию аппликативного стиля:
f :: String -> String -> IO String
f x y = withHyp <[110]gt; getEnv x <*> getEnv y
where withHyp ex ey = ex ++ '-' : ey
Итак, здесь мы объединяем две String
, которые затем соединяются с гипеном в середине через функцию withHyp
.
Или для списка переменных среды, которые нам нужно выбрать, мы можем использовать mapM
и выполнить intercalate
:
import Data.List(intercalate)
f :: [String] -> IO String
f xs = intercalate "-" <[111]gt; mapM getEnv xs
Я буду честен, идея вашего подхода на самом деле выглядит довольно вменяемой для меня. Начнем с того, что я, вероятно, использовал бы concat
intsead из foldl1 (++)
и отбросил бы несколько паренов, чтобы заставить нас:
f x y = concat <[110]gt; sequence [getEnv x, return "-", getEnv y]
Это действительно не кажется мне таким уж плохим. Но если бы я действительно хотел продвинуться дальше, вот некоторые мысли, которые у меня были бы. Во-первых, я бы вспомнил функцию intercalate
.
f x y = intercalate "-" <[111]gt; sequence [getEnv x, getEnv y]
Есть удобное сокращение для применения функции к каждому элементу списка; mapM f = sequence . map f
. Итак:
f x y = intercalate "-" <[112]gt; mapM getEnv [x,y]
Я бы остановился на этом; это выглядит довольно чистым и ремонтопригодным для меня.
Один из способов объединить два IO String
:
dash :: IO String -> IO String -> IO String
dash x y = do
s1 <- x
s2 <- y
return $ s1 <> "-" <> s2
. Мы «распаковываем» каждый из x
и y
, чтобы получить содержащиеся в нем String
, затем «rebox» их с дефисом (используя аналогию для функторов).
Его можно сократить до:
dash = liftA2 (\s1 s2 -> s1 <> "-" <> s2)
где liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
берет двоичную функцию и «поднимает» ее в двоичную функцию на Applicative
с, которые являются надмножеством Monad
с.
Ваш f
может быть затем реализован как f x y = dash (getEnv x) (getEnv y)
.