Это упрощенная версия проблемы, с которой я сталкиваюсь (так что функционально это не имеет смысла, но это проблема типа).
module EGBase where
import Prelude
newtype SomeData a b = SomeData String
module EGChild where
import EGBase
import Prelude
myData :: SomeData Int Int
myData = SomeData "Child"
module EGChild1 where
import EGBase
import Prelude
myData :: SomeData Int String
myData = SomeData "Child 1"
module EGMain where
import EGBase
import EGChild
import EGChild1
import Prelude
worker1 :: SomeData a b -> IO ()
worker1 _ = putStrLn "Hello from Worker 1"
worker2 :: SomeData a b -> IO ()
worker2 _ = putStrLn "Hello from Worker 2"
mergeThem :: [IO ()] -> IO ()
mergeThem = foldl (>>) (pure ())
main1 :: IO ()
main1 = mergeThem [
worker1 EGChild.myData,
worker1 EGChild1.myData
]
main2 :: IO ()
main2 = mergeThem [
worker2 EGChild.myData,
worker2 EGChild1.myData
]
Приведенные выше компиляции, но в реальном приложении у меня потенциально будет много разных работников, которых я хочу подать насписок множества модулей (создание множества версий приложения).Я хотел бы снять, а не жестко закодировать рабочую функцию.
В качестве первого шага я попытался просто вытащить жестко закодированного работника из списка, но это не сработало, потому что элементы списка не были одинаковыми.введите:
-- different types in list [SomeData Int Int, SomeData Int String]
main2Dry :: IO ()
main2Dry = mergeThem $ worker2 <$> [
EGChild.myData,
EGChild1.myData
]
Что мне действительно нужно, так это что-то вроде этого, но это не будет работать по той же причине, что и выше:
mainShared :: (SomeData a b -> IO ()) -> IO ()
mainShared worker = mergeThem $ worker <$> [
EGChild.myData,
EGChild1.myData
]
Следующее тоже будет хорошо, но я думаю,проблема здесь в том, что конкретный тип рабочей функции выводится из первого элемента в списке, что означает, что существуют проблемы, когда рабочий применяется ко второму элементу:
mainShared :: (SomeData a b -> IO ()) -> IO ()
mainShared worker = mergeThem [
worker EGChild.myData,
worker EGChild1.myData
]
--
-- does not compile
--
-- src\EGMain.hs:50:28-42: error:
-- * Couldn't match type `b' with `String'
-- `b' is a rigid type variable bound by
-- the type signature for:
-- mainShared :: forall a b. (SomeData a b -> IO ()) -> IO ()
-- at src\EGMain.hs:47:1-46
-- Expected type: SomeData a b
-- Actual type: SomeData Int String
-- * In the first argument of `worker', namely `EGChild1.myData'
-- In the expression: worker EGChild1.myData
-- In the first argument of `mergeThem', namely
-- `[worker EGChild.myData, worker EGChild1.myData]'
Так вот, что я пытаюсьдобиться возможности в Haskell?