Out of sheer curiosity, I wonder of something like the following is possible in Haskell:
A function foo
takes another function as an argument that is called in the body of foo
more than once, changing the type of the arguments along the way.
This following code does not compile because fn
's argument's types are pinned down once it is called, but hopefully it illustrates what I'm babbling about.
main = putStrLn (foo id)
foo :: (* -> *) -> [Char] -- maybe I'm also getting the whole *-thing wrong
foo fn =
let
val1 = fn "hey"
val2 = fn 42
in
show (val1, val2)
I wonder if it can be achieved at all, and if you can do it without helpers like typeclasses.
What you're looking for is an extension called RankNTypes
. With it, you can write the type of your function as:
{-# LANGUAGE RankNTypes #-}
foo :: (forall a. a -> a) -> [Char]
In this case, the only function you can possibly supply is id
, but you can also use type classes to allow slightly more interesting polymorphic functions as arguments. Consider this version of your function:
bar:: (forall a. Show a => a -> String) -> String
bar fn =
let
val1 = fn "hey"
val2 = fn 42
in
val1 <> val2
*
is not a wildcard to allow any type to be used. Therefore, you use of that is wrong.
To type your function, we need to specify the type of fn
. That must be a polymorphic function returning some value that can be Show
ed.
A possible solution is:
{-# LANGUAGE ScopedTypeVariables, RankNTypes #-}
foo :: forall b. Show b => (forall a. a -> b) -> [Char]
foo fn = let
val1 = fn "hey"
val2 = fn 42
in show (val1, val2)
This requires fn
to accept any type a
and return a fixed type b
which is of class Show
.
As written, this is not terribly useful since there is no way that fn
can make use of its argument, since it is of a generic type a
.
Perhaps a more useful variant could be one where a
belongs to some typeclass c
, so that at least the argument of fn
can be used according to c
.
foo :: forall b c. (Show b, c String, c Int)
=> (forall a. c a => a -> b) -> [Char]
foo fn = let
val1 = fn "hey"
val2 = fn (42 :: Int)
in show (val1, val2)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With