Не совсем понятно, что вы имеете в виду, но, основываясь на комментариях, вот несколько предложений.
Параметрическая функция
Как дано, f
возвращает (Int, String)
, и вы не можете просто изменить это. Тем не менее, вы можете настроить его следующим образом:
f' :: a -> a -> Int -> (Int, a)
f' bigger smaller x | x > 3 = (x, bigger)
| otherwise = (x, smaller)
Этот вариант больше не возвращает (Int, String)
, а скорее (Int, a)
. Однако цена, которую вы платите, заключается в том, что вы должны предоставить bigger
и smaller
в качестве аргументов. Мы вернемся к этому через мгновение, но прежде чем мы это сделаем, мы можем превратить любую функцию с общим типом s -> (s, a)
в значение State s a
:
make' :: (s -> (s, a)) -> State s a
make' fn = State fn
Теперь вы можете частично применить f'
для изменения типа:
*Q56181862> :t make' $ f' "bigger than 3" "smaller than 3"
make' $ f' "bigger than 3" "smaller than 3" :: State Int [Char]
*Q56181862> :t make' $ f' True False
make' $ f' True False :: State Int Bool
В первом из приведенных выше примеров GHCi типом является State Int String
, тогда как второй пример имеет тип State Int Bool
.
Возвращение
Из других комментариев кажется, что вы хотите варьироваться от State Int String
до State Int (IO String)
. Хотя вы можете добиться этого с помощью описанной выше техники, вы также можете использовать return
в самой функции:
f'' :: Monad m => Int -> (Int, m String)
f'' x | x > 3 = (x, return "bigger than 3")
| otherwise = (x, return "smaller than 3")
Это меняет только монаду, но не «тип возврата» String
. Вы можете предоставить достаточно подсказок системе типов Haskell, чтобы сообщить, что m
должно быть IO
:
*Q56181862> :t make' $ f'' :: State Int (IO String)
make' $ f'' :: State Int (IO String) :: State Int (IO String)
Если вы не хотите запускать вычисления в IO
, вы можете вместо этого запустить их в Identity
, что также является Monad
:
*Q56181862 Control.Monad.Identity> :t make' $ f'' :: State Int (Identity String)
make' $ f'' :: State Int (Identity String) :: State Int (Identity String)
Теперь вы можете запустить вычисление и извлечь String
из Identity
, используя runIdentity
.
Functor
Если вы также сделаете State s
функтором, вы можете извлечь String
из Identity
:
*Q56181862 Control.Monad.Identity> :t fmap runIdentity $ make' $ f''
fmap runIdentity $ make' $ f'' :: State Int String
Самый простой способ сделать это - использовать расширение DeriveFunctor
GHC:
newtype State s a = State { runstate :: s -> (s, a) } deriving Functor
... или вы можете просто использовать Control.Monad.State.Lazy
из пакета mtl
...