How can I apply a function to every argument of another function? - haskell

I have a function that takes 10 String parameters and during some refactoring, portions of the code have changed so now these parameters end up as Text when the function is called:
fxn :: String -> ... -> IO (Int, String)
fxn a b c d e f g h i j = do something
...
-- Get parameters for fxn
let a = "blah" :: Text
...
fxn a b c ...
Ideally, I could refactor all of the code to use Text, but that is tedious and non ideal currently. I could also easily add a T.unpack to where I get the parameters for my function:
let a = T.unpack ("blah" :: Text)
But again, this is non ideal since this happens in several different places for large numbers of arguments and I'd prefer to keep the code cleaner than having dozens of T.unpack statements everywhere.
Is there a way in haskell to either compose the functions so that the arguments are morphed, something like (fxn . T.unpack) a b c ..., or to apply the unpack function to every argument of the f function? This seems like a simple composition problem but I haven't been able to find a solution.

For dealing with the parameter proliferation, you may like the record parameter pattern. This also makes it convenient to expose a new API with the same name while maintaining backwards compatibility.
For the question as asked, it's usually simplest to define a short adapter like this:
fxnNew :: Text -> ... -> IO (Int, Text)
fxnNew = ...
fxn :: String -> ... -> IO (Int, String)
fxn a ... i = fmap (fmap T.unpack) (fxnNew (T.pack a) ... (T.pack i))

Related

Why does this function work even though the argument is missing?

I'm trying to understand the following piece of code:
import Data.Char (ord)
encodeInteger :: String -> Integer
encodeInteger = read . concatMap ch
where ch c = show (ord c)
But I don't see how this can work when encodeInteger is defined as a function that takes a string, but in the second line, the function is implemented without that string argument.
Also, concatMap (according to hoogle), takes a function and a list, but only the function ch is provided.
Why does this code still work? Is the argument somehow magically passed? Has it something to do with currying?
edit: And why doesn't it work to change it like this:
encodeInteger :: String -> Integer
encodeInteger a = read . concatMap ch a
where ch c = show (ord c)
Basically defining a function
f = g
is the same as defining the function
f x = g x
In your specific case, you can use
encodeInteger a = (read . concatMap ch) a
to define your function. The parentheses are needed, otherwise it is parsed as
encodeInteger a = (read) . (concatMap ch a)
and concatMap ch a is not a function and can not be composed. At most you could write
encodeInteger a = read (concatMap ch a)
-- or
encodeInteger a = read $ concatMap ch a
About "why concatMap ch takes only one argument?". This is a partial application, which is very common in Haskell. If you have
f x y z = x+y+z
you can call f with fewer arguments, and obtain as the result a function of the remaining arguments. E.g., f 1 2 is the function taking z and returning 1+2+z.
Concretely, thanks to Currying, there's no such a thing as a function taking two or more arguments. Every function always takes only one argument. When you have a function like
foo :: Int -> Bool -> String
then foo takes one argument, an Int. It returns a function, which takes a Bool and finally returns a String. You can visualize this by writing
foo :: Int -> (Bool -> String)
Anyway, if you look up currying and partial application, you will find plenty of examples.
encodeInteger :: String -> Integer
encodeInteger = read.concatMap (\char -> show $ ord char)
The encodeInteger on the left hand side (LHS) of "=" is a name; it refers to the function on the right hand side (RHS) of "=". Both have the function type: String -> Integer. Both take a list of characters and produces an integer. Haskell enables us to express such function equality without specifying formal arguments (a style known as point-free).
Now, let's look at the RHS. The (.) operator composes two functions together. The composed function takes a string as its input from concatMap and produces an integer coming out of read as the output of the composed function.
concatMap itself takes 2 inputs, but we need to leave out the second one for the composed function, which requires a string as its input. We achieve this by partially applying concatMap, including only its first argument.

Haskell - Accepting different types and acting accordingly

Lets say I got the following very basic example:
f :: Either Int String -> IO ()
as well as a function g :: Int -> IO () and a function g' :: String -> IO () and I basically want to implement f as a "selector" which calls g or g' depending on its input, so that in the future I only have to work with f because I know that my program will only encounter either Int or String.
Does this way of using Either make sense? The convention seems to be to use it mainly for Error and Exception handling.
If it does make sense, what would be a good way or best practice to implement such an example? I've heard/read about case as well as bifunctors.
If it does not: what is the haskell way of handling the possibility of different input types? Or is this something which should be avoided from the beginning?
So that definitely can make sense and one way to implement that is:
f :: Either Int String -> IO ()
f e =
case e of
Left l -> g l
Right r -> g' r
or using either:
import Data.Either (either)
f :: Either Int String -> IO ()
f = either g g'
Note that in the second version I don't assign a variable name to the Either Int String argument. That is called eta conversion / eta reduction. But obviously you could also write f e = either g g' e.
As an armchair Haskell programmer, it seems fine to me.
f :: Either Int String -> IO ()
f (Left n) = g n
f (Right s) = g' s

Get the value out of Just constructor [duplicate]

I have a function that has a return type of Maybe ([(Int,Int)],(Int,Int))
I would like to call this from another function and perform an operation on the data.
However, the return value is contained within Just. The second method takes ([(Int,Int)],(Int,Int)) and therefore will not accept Just ([(Int,Int)],(Int,Int)).
Is there a way I can trim the Just before applying the second method?
I don't fully understand the use of Just within Maybe - however, I have been told that the return type for the first Method must be Maybe.
There are several solutions to your problem, all based around pattern matching. I'm assuming you have two algorithms (since you didn't name them, I will):
algorithm1 :: a -> Maybe b
algorithm2 :: b -> c
input :: a
1) Pattern matching is typically done from either a case statement (below) or a function.
let val = algorithm1 input
in case val of
Nothing -> defaultValue
Just x -> algorithm2 x
All other presented solutions use pattern matching, I'm just presenting standard functions that perform the pattern matching for you.
2) The prelude (and Data.Maybe) have some built-in functions to deal with Maybes. The maybe function is a great one, I suggest you use it. It's defined in standard libraries as:
maybe :: c -> (b -> c) -> Maybe b -> c
maybe n _ Nothing = n
maybe _ f (Just x) = f x
Your code would look like:
maybe defaultValue algorithm2 (algorithm1 input)
3) Since Maybe is a functor you could use fmap. This makes more sense if you don't have a default value. The definition:
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
So your code would look like:
fmap algorithm2 (algorithm1 input)
This output will be a Maybe value (Nothing if the result of algorithm1 is Nothing).
4) Finally, and strongly discouraged, is fromJust. Only use it if you are positive the first algorithm will return Just x (and not Nothing). Be careful! If you call fromJust val when val = Nothing then you get an exception, which is not appreciated in Haskell. Its definition:
fromJust :: Maybe b -> b
fromJust Nothing = error "Maybe.fromJust: Nothing" -- yuck
fromJust (Just x) = x
Leaving your code to look like:
algorithm2 (fromJust (algorithm1 input))
You're looking for fromJust. But only if you're certain your Maybe function is not going to return a Nothing!

Match Data constructor functions

I'm trying to match data constructors in a generic way, so that any Task of a certain type will be executed.
data Task = TaskTypeA Int | TaskTypeB (Float,Float)
genericTasks :: StateLikeMonad s
genericTasks = do
want (TaskTypeA 5)
TaskTypeA #> \input -> do
want (TaskTypeB (1.2,4.3))
runTaskTypeA input
TaskTypeB #> \(x,y) -> runTaskTypeB x y
main = runTask genericTasks
In this, the genericTasks function goes through the do-instructions, building a list of stuff to do from want handled by some sort of state monad, and a list of ways to do it, via the (#>) function. The runTask function will run the genericTasks, use the resulting list of to-do and how-to-do, and do the computations.
However, I'm having quite some trouble figuring out how to extract the "type" (TaskTypeA,B) from (#>), such that one can call it later. If you do a :t TaskTypeA, you get a Int -> Task.
I.e., How to write (#>)?
I'm also not entirely confident that it's possible to do what I'm thinking here in such a generic way. For reference, I'm trying to build something similar to the Shake library, where (#>) is similar to (*>). However Shake uses a String as the argument to (*>), so the matching is done entirely using String matching. I'd like to do it without requiring strings.
Your intuition is correct, it's not possible to write (#>) as you have specified. The only time a data constructor acts as a pattern is when it is in pattern position, namely, appearing as a parameter to a function
f (TaskTypeA z) = ...
as one of the alternatives of a case statement
case tt of
TaskTypeA z -> ...
or in a monadic or pattern binding
do TaskTypeA z <- Just tt
return z
When used in value position (e.g. as an argument to a function), it loses its patterny nature and becomes a regular function. That means, unfortunately, that you cannot abstract over patterns this easily.
There is, however, a simple formalization of patterns:
type Pattern d a = d -> Maybe a
It's a little bit of work to make them.
taskTypeA :: Pattern Task Int
taskTypeA (TaskTypeA z) = Just z
taskTypeA _ = Nothing
If you also need need to use the constructor "forwards" (i.e. a -> d), then you could pair the two together (plus some functions to work with it):
data Constructor d a = Constructor (a -> d) (d -> Maybe a)
apply :: Constructor d a -> a -> d
apply (Constructor f _) = f
match :: Constructor d a -> d -> Maybe a
match (Constructor _ m) = m
taskTypeA :: Constructor Task Int
taskTypeA = Constructor TaskTypeA $ \case TaskTypeA z -> Just z
_ -> Nothing
This is known as a "prism", and (a very general form of) it is implemented in lens.
There are advantages to using an abstraction like this -- namely, that you can construct prisms which may have more structure than data types are allowed to (e.g. d can be a function type), and you can write functions that operate on constructors, composing simpler ones to make more complex ones generically.
If you are using plain data types, though, it is a pain to have to implement the Constructor objects for each constructor like I did for TaskTypeA above. If you have a lot of these to work with, you can use Template Haskell to write your boilerplate for you. The necessary Template Haskell routine is already implemented in lens -- it may be worth it to learn how to use the lens library because of that. (But it can be a bit daunting to navigate)
(Style note: the second Constructor above and its two helper functions can be written equivalently using a little trick:
data Constructor d a = Constructor { apply :: a -> d, match :: d -> Maybe a }
)
With this abstraction in place, it is now possible to write (#>). A simple example would be
(#>) :: Constructor d a -> (a -> State d ()) -> State d ()
cons #> f = do
d <- get
case match cons d of
Nothing -> return ()
Just a -> f a
or perhaps something more sophisticated, depending on what precisely you want.

Haskell data serialization of some data implementing a common type class

Let's start with the following
data A = A String deriving Show
data B = B String deriving Show
class X a where
spooge :: a -> Q
[ Some implementations of X for A and B ]
Now let's say we have custom implementations of show and read, named show' and read' respectively which utilize Show as a serialization mechanism. I want show' and read' to have types
show' :: X a => a -> String
read' :: X a => String -> a
So I can do things like
f :: String -> [Q]
f d = map (\x -> spooge $ read' x) d
Where data could have been
[show' (A "foo"), show' (B "bar")]
In summary, I wanna serialize stuff of various types which share a common typeclass so I can call their separate implementations on the deserialized stuff automatically.
Now, I realize you could write some template haskell which would generate a wrapper type, like
data XWrap = AWrap A | BWrap B deriving (Show)
and serialize the wrapped type which would guarantee that the type info would be stored with it, and that we'd be able to get ourselves back at least an XWrap... but is there a better way using haskell ninja-ery?
EDIT
Okay I need to be more application specific. This is an API. Users will define their As, and Bs and fs as they see fit. I don't ever want them hacking through the rest of the code updating their XWraps, or switches or anything. The most i'm willing to compromise is one list somewhere of all the A, B, etc. in some format. Why?
Here's the application. A is "Download a file from an FTP server." B is "convert from flac to mp3". A contains username, password, port, etc. information. B contains file path information. There could be MANY As and Bs. Hundreds. As many as people are willing to compile into the program. Two was just an example. A and B are Xs, and Xs shall be called "Tickets." Q is IO (). Spooge is runTicket. I want to read the tickets off into their relevant data types and then write generic code that will runTicket on the stuff read' from the stuff on disk. At some point I have to jam type information into the serialized data.
I'd first like to stress for all our happy listeners out there that XWrap is a very good way, and a lot of the time you can write one yourself faster than writing it using Template Haskell.
You say you can get back "at least an XWrap", as if that meant you couldn't recover the types A and B from XWrap or you couldn't use your typeclass on them. Not true! You can even define
separateAB :: [XWrap] -> ([A],[B])
If you didn't want them mixed together, you should serialise them seperately!
This is nicer than haskell ninja-ery; maybe you don't need to handle arbitrary instances, maybe just the ones you made.
Do you really need your original types back? If you feel like using existential types because you just want to spooge your deserialised data, why not either serialise the Q itself, or have some intermediate data type PoisedToSpooge that you serialise, which can deserialise to give you all the data you need for a really good spooging. Why not make it an instance of X too?
You could add a method to your X class that converts to PoisedToSpooge.
You could call it something fun like toPoisedToSpooge, which trips nicely off the tongue, don't you think? :)
Anyway this would remove your typesystem complexity at the same time as resolving the annoying ambiguous type in
f d = map (\x -> spooge $ read' x) d -- oops, the type of read' x depends on the String
You can replace read' with
stringToPoisedToSpoogeToDeserialise :: String -> PoisedToSpooge -- use to deserialise
and define
f d = map (\x -> spooge $ stringToPoisedToSpoogeToDeserialise x) -- no ambiguous type
which we could of course write more succincly as
f = map (spooge.stringToPoisedToSpoogeToDeserialise)
although I recognise the irony here in suggesting making your code more succinct. :)
If what you really want is a heterogeneous list then use existential types. If you want serialization then use Cereal + ByteString. If you want dynamic typing, which is what I think your actual goal is, then use Data.Dynamic. If none of this is what you want, or you want me to expand please press the pound key.
Based on your edit, I don't see any reason a list of thunks won't work. In what way does IO () fail to represent both the operations of "Download a file from an FTP server" and "convert from flac to MP3"?
I'll assume you want to do more things with deserialised Tickets
than run them, because if not you may as well ask the user to supply a bunch of String -> IO()
or similar, nothing clever needed at all.
If so, hooray! It's not often I feel it's appropriate to recommend advanced language features like this.
class Ticketable a where
show' :: a -> String
read' :: String -> Maybe a
runTicket :: a -> IO ()
-- other useful things to do with tickets
This all hinges on the type of read'. read' :: Ticket a => String -> a isn't very useful,
because the only thing it can do with invalid data is crash.
If we change the type to read' :: Ticket a => String -> Maybe a this can allow us to read from disk and
try all the possibilities or fail altogether.
(Alternatively you could use a parser: parse :: Ticket a => String -> Maybe (a,String).)
Let's use a GADT to give us ExistentialQuantification without the syntax and with nicer error messages:
{-# LANGUAGE GADTs #-}
data Ticket where
MkTicket :: Ticketable a => a -> Ticket
showT :: Ticket -> String
showT (MkTicket a) = show' a
runT :: Ticket -> IO()
runT (MkTicket a) = runTicket a
Notice how the MkTicket contstuctor supplies the context Ticketable a for free! GADTs are great.
It would be nice to make Ticket and instance of Ticketable, but that won't work, because there would be
an ambiguous type a hidden in it. Let's take functions that read Ticketable types and make them read
Tickets.
ticketize :: Ticketable a => (String -> Maybe a) -> (String -> Maybe Ticket)
ticketize = ((.).fmap) MkTicket -- a little pointfree fun
You could use some unusual sentinel string such as
"\n-+-+-+-+-+-Ticket-+-+-+-Border-+-+-+-+-+-+-+-\n" to separate your serialised data or better, use separate files
altogether. For this example, I'll just use "\n" as the separator.
readTickets :: [String -> Maybe Ticket] -> String -> [Maybe Ticket]
readTickets readers xs = map (foldr orelse (const Nothing) readers) (lines xs)
orelse :: (a -> Maybe b) -> (a -> Maybe b) -> (a -> Maybe b)
(f `orelse` g) x = case f x of
Nothing -> g x
just_y -> just_y
Now let's get rid of the Justs and ignore the Nothings:
runAll :: [String -> Maybe Ticket] -> String -> IO ()
runAll ps xs = mapM_ runT . catMaybes $ readTickets ps xs
Let's make a trivial ticket that just prints the contents of some directory
newtype Dir = Dir {unDir :: FilePath} deriving Show
readDir xs = let (front,back) = splitAt 4 xs in
if front == "dir:" then Just $ Dir back else Nothing
instance Ticketable Dir where
show' (Dir p) = "dir:"++show p
read' = readDir
runTicket (Dir p) = doesDirectoryExist p >>= flip when
(getDirectoryContents >=> mapM_ putStrLn $ p)
and an even more trivial ticket
data HelloWorld = HelloWorld deriving Show
readHW "HelloWorld" = Just HelloWorld
readHW _ = Nothing
instance Ticketable HelloWorld where
show' HelloWorld = "HelloWorld"
read' = readHW
runTicket HelloWorld = putStrLn "Hello World!"
and then put it all together:
myreaders = [ticketize readDir,ticketize readHW]
main = runAll myreaders $ unlines ["HelloWorld",".","HelloWorld","..",",HelloWorld"]
Just use Either. Your users don't even have to wrap it themselves. You have your deserializer wrap it in the Either for you. I don't know exactly what your serialization protocol is, but I assume that you have some way to detect which kind of request, and the following example assumes the first byte distinguishes the two requests:
deserializeRequest :: IO (Either A B)
deserializeRequest = do
byte <- get1stByte
case byte of
0 -> do
...
return $ Left $ A <A's fields>
1 -> do
...
return $ Right $ B <B's fields>
Then you don't even need to type-class spooge. Just make it a function of Either A B:
spooge :: Either A B -> Q

Resources