I have an application that extracts information from different data sources. Since the extraction process is the same, except some steps, I have abstracted such different steps in corresponding classes, and I instantiate and pass each object to a generic search procedure. I suppose that -- in Erlang -- I would use a record of functions instead of an object, right?
In case my description is not clear, here is some very simplified pseudo-code:
class Query1:
def query_a(data):
...
def query_b(data):
...
class Query2:
def query_a(data):
...
def query_b(data):
...
def extract_info(data,query):
# Calls the methods `query_a` and `query_b` of `query`.
# `query` can be either a `Query1` object or a `Query2` object.
You have couple of options:
You can pass both query_a and query_b as anonymous functions.
extract_info(Data, QueryA, QueryB) ->
A = QueryA(Data),
B = QueryB(Data),
...
extract_info(Data, fun({A, _B} -> A end, fun {_A, B} -> B end).
If the query logic is complex, you can define modules query_a and query_b and pass single atom to extract info:
-module(query1).
-compile([export_all]).
query_a({A, _B}) ->
A.
query_b({_A, B}) ->
B.
query2 module would be analogus.
-module(other_module).
...
extract_info(Data, Query) ->
A = Query:query_a(Data),
B = Query:query_b(Data)
...
extract_info(Data, query1).
If the query logic depends only on data source, you can use function clauses that pattern match on different types. Lets say, that your data are tuples. Type one is something like this {A, B}, and second type is something like this {{data1, A}, {data2, B}}
query_a({A, _B}) ->
A;
query_a({{data1, A}, {data2, _B}}) ->
A.
query_b({_A, B}) ->
B;
query_b({{data1, _A}, {data2, B}}) ->
B.
extract_info(Data) ->
A = query_a(Data),
B = query_b(Data).
If the data sources are similar, you can always tag the tuples with single atom like: {data1, A, B} and {data2, A, B}. The last option is the most idiomatic if the query logic depends only on data type. For different queries, you have to use one of the previous ones.
Related
I'm trying to build a generic mapping function that will extract a possible inner type from a union type, apply a transform to the inner value and map it back to the outer type.
The trouble is, I need a way to distinguish if a specific value of the outer type has an inner type at all.
It would work for me if the code below actually compiled, but Elm doesn't allow constants in pattern matches. (constructor on line 4 fails to compile)
Is there any other way to accomplish this?
map : (inner -> outer) -> (inner -> inner) -> outer -> outer
map constructor func current =
case current of
constructor child ->
constructor (func child)
_ ->
current
No, unfortunately Elm doesn't have a way to express this kind of thing generically, you need to write a specific version for each custom type.
You can take a look to the elm-accessors library. With it you will need to define a Relation for every of yours type constructor (it is pretty straightforward). But then you'll be free to use a good old List.map to map over any constructor!
Here is a usage example:
type FooBar a b
= Foo a
| Bar b
items =
List.map
(over (foo << try) ((+) 1) -- affects only "Foo"s
<<
over (bar << try) (\b -> b ++ "!")) -- affects only "Bar"s
[Foo 1, Bar "a", Foo 10]
-- = [Foo 2,Bar "a!",Foo 11]
Here is a live version (Ellie).
I would like to make a function that given a function type (e.g. String -> Nat -> Bool), would return a list of types corresponding to that function type (e.g. [String, Nat, Bool]). Presumably the signature of such a function would be Type -> List Type, but I am struggling to determine how it would be implemented.
I don't believe it could be done in general, because you cannot patter-match on functions. Neither can you check for the type of a function. That is not what dependent types are about. Just like in Haskell or OCaml the only thing you can actually do with a function is apply it to some argument. However, I devised some trick which might do:
myFun : {a, b : Type} -> (a -> b) -> List Type
myFun {a} {b} _ = [a, b]
Now the problem is that a -> b is the only signature that would match any arbitrary function. But, of course it does not behave the way you'd like for functions with arity higher than one:
> myFun (+)
[Integer, Integer -> Integer] : List Type
So some sort of recursive call to itself would be necessary to extract more argument types:
myFun : {a, b : Type} -> (a -> b) -> List Type
myFun {a} {b} _ = a :: myFun b
The problem here is that b is an arbitrary type, not necessarily a function type and there is no way I can figure out to dynamically check whether it is a function or not, so I suppose this is as much as you can do with Idris.
However, dynamic checking for types (at least in my opinion) is not a feature to be desired in a statically typed language. After all the whole point of static typing is to specify in advance what kind of arguments a function can handle and prevent calling functions with invalid arguments at compile time. So basically you probably don't really need it at all. If you specified what you grander goal was, someone would likely have shown you the right way of doing it.
I can define a tagged unions type like that:
type Msg
= Sort (Product -> Float)
But I cannot define it like:
type Msg
= Sort (Product -> comparable)
The error says:
Type Msg must declare its use of type variable comparable...
But comparable is a pre-defined type variable, right?
How do I fix this?
This question feels a little like an XY Problem. I'd like to offer a different way of thinking about passing sorting functions around in your message (with the caveat that I'm not familiar with your codebase, only the examples you've given in your question).
Adding a type parameter to Msg does seem a bit messy so let's take a step back. Sorting involves comparing two of the same types in a certain way and returning whether the first value is less than, equal to, or greater than the second. Elm already has an Order type using for comparing things which has the type constructors LT, EQ, and GT (for Less Than, EQual, and Greater Than).
Let's refactor your Msg into the following:
type Msg
= Sort (Product -> Product -> Order)
Now we don't have to add a type parameter to Msg. But how, then, do we specify which field of Product to sort by? We can use currying for that. Here's how:
Let's define another function called comparing which takes a function as its first argument and two other arguments of the same type, and return an Order value:
comparing : (a -> comparable) -> a -> a -> Order
comparing f x y =
compare (f x) (f y)
Notice the first argument is a function that looks similar to what your example was trying to attempt in the (Product -> comparable) argument of the Sort constructor. That's no coincidence. Now, by using currying, we can partially apply the comparing function with a record field getter, like .name or .price. To amend your example, the onClick handler could look like this:
onClick (Sort (comparing .name))
If you go this route, there will be more refactoring. Now that you have this comparison function, how do you use it in your update function? Let's assume your Model has a field called products which is of type List Product. In that case, we can just use the List.sortWith function to sort our list. Your update case for the Sort Msg would look something like this:
case msg of
Sort comparer ->
{ model | products = List.sortWith comparer model.products } ! []
A few closing thoughts and other notes:
This business about a comparing function comes straight from Haskell where it fulfills the same need.
Rather than defining the Sort constructor as above, I would probably abstract it out a little more since it is such a common idiom. You could define an alias for a generalized function like this, then redefine Msg as shown here:
type alias Comparer a =
a -> a -> Order
type Msg
= Sort (Comparer Product)
And to take it one step further just to illustrate how this all connects, the following two type annotations for comparing are identical:
-- this is the original example from up above
comparing : (a -> comparable) -> a -> a -> Order
-- this example substitutues the `Comparer a` alias, which may help further
-- your understanding of how it all ties together
comparing : (a -> comparable) -> Comparer a
The error you're getting is saying that comparable is an unbound variable type. You need to either fully specify it on the right hand side (e.g. Product -> Int) or specify you would like it to be polymorphic on the left hand side. Something like this:
type Msg a = Sort (Product -> a)
The question you ask about comparable is answered here: What does comparable mean in Elm?
Why are the arguments ordered the way they are in Array.get and Dict.get? The order in most map/filter functions makes sense: the function comes before the collection (or monad, more generally).
MyCollection.map : (a -> b) -> MyCollection a -> MyCollection b
This makes it easier to compose higher functions out of smaller ones before passing in a collection.
Why, however, does the index/key come before the collection in get functions?
Dict.get : comparable -> Dict comparable v -> Maybe v
It seems to make it harder to compose higher functions. If the arguments were reversed, one could write:
ids : List Int
myObjects : Dict Int a
selectObjects = List.map (Dict.get myObjects) ids
But instead, the best way I can come up with to write this is:
ids : List Int
myObjects : Dict Int a
selectObjects = List.map (\id -> (Dict.get id myObjects)) ids
Am I missing something? What is the reason for the argument order in Array.get, Dict.get, and similar?
List.map (Dict.get myObjects) ids isn't function composition.
Composition is when you have
f : X -> Y and
g : Y -> Z then you compose them
h = f >> g so that
h : X -> Z
Now, when composing functions as above, we need them to require ONLY one more parameter.
So when defining an API, the question is:
"When someone partially evaluates this function so that it can be composed, what is the last parameter they'll likely want to pass it?"
In other words, are we more likely to see code like:
getStuff >> mungeIntoDict >> (Dict.get id)
or
getStuff >> getImportantId >> (Dict.get myDict)
?
The answer to that is "it depends". The API designers took their best guess and we have flip for when it doesn't suit us.
Suppose I am defining a Haskell function f (either pure or an action) and somewhere within f I call function g. For example:
f = ...
g someParms
...
How do I replace function g with a mock version for unit testing?
If I were working in Java, g would be a method on class SomeServiceImpl that implements interface SomeService. Then, I'd use dependency injection to tell f to either use SomeServiceImpl or MockSomeServiceImpl. I'm not sure how to do this in Haskell.
Is the best way to do it to introduce a type class SomeService:
class SomeService a where
g :: a -> typeOfSomeParms -> gReturnType
data SomeServiceImpl = SomeServiceImpl
data MockSomeServiceImpl = MockSomeServiceImpl
instance SomeService SomeServiceImpl where
g _ someParms = ... -- real implementation of g
instance SomeService MockSomeServiceImpl where
g _ someParms = ... -- mock implementation of g
Then, redefine f as follows:
f someService ... = ...
g someService someParms
...
It seems like this would work, but I'm just learning Haskell and wondering if this is the best way to do this? More generally, I like the idea of dependency injection not just for mocking, but also to make code more customizable and reusable. Generally, I like the idea of not being locked into a single implementation for any of the services that a piece of code uses. Would it be considered a good idea to use the above trick extensively in code to get the benefits of dependency injection?
EDIT:
Let's take this one step further. Suppose I have a series of functions a, b, c, d, e, and f in a module that all need to be able to reference functions g, h, i, and j from a different module. And suppose I want to be able to mock functions g, h, i, and j. I could clearly pass the 4 functions in as parameters to a-f, but that's a bit of a pain to add the 4 parameters to all the functions. Plus, if I ever needed to change the implementation of any of a-f to call yet another method, I'd need to change its signature, which could create a nasty refactoring exercise.
Any tricks to making this type of situation work easily? For example, in Java, I could construct an object with all of its external services. The constructor would store the services off in member variables. Then, any of the methods could access those services via the member variables. So, as methods are added to services, none of the method signatures change. And if new services are needed, only the constructor method signature changes.
Why use unit testing when you can have Automated Specification-Based Testing? The QuickCheck library does this for you. It can generate arbitrary (mock) functions and data using the Arbitrary type-class.
"Dependency Injection" is a degenerate form of implicit parameter passing. In Haskell, you can use Reader, or Free to achieve the same thing in a more Haskelly way.
Another alternative:
{-# LANGUAGE FlexibleContexts, RankNTypes #-}
import Control.Monad.RWS
data (Monad m) => ServiceImplementation m = ServiceImplementation
{ serviceHello :: m ()
, serviceGetLine :: m String
, servicePutLine :: String -> m ()
}
serviceHelloBase :: (Monad m) => ServiceImplementation m -> m ()
serviceHelloBase impl = do
name <- serviceGetLine impl
servicePutLine impl $ "Hello, " ++ name
realImpl :: ServiceImplementation IO
realImpl = ServiceImplementation
{ serviceHello = serviceHelloBase realImpl
, serviceGetLine = getLine
, servicePutLine = putStrLn
}
mockImpl :: (Monad m, MonadReader String m, MonadWriter String m) =>
ServiceImplementation m
mockImpl = ServiceImplementation
{ serviceHello = serviceHelloBase mockImpl
, serviceGetLine = ask
, servicePutLine = tell
}
main = serviceHello realImpl
test = case runRWS (serviceHello mockImpl) "Dave" () of
(_, _, "Hello, Dave") -> True; _ -> False
This is actually one of the many ways to create OO-styled code in Haskell.
To follow up on the edit asking about multiple functions, one option is to just put them in a record type and pass the record in. Then you can add new ones just by updating the record type. For example:
data FunctionGroup t = FunctionGroup { g :: Int -> Int, h :: t -> Int }
a grp ... = ... g grp someThing ... h grp someThingElse ...
Another option that might be viable in some cases is to use type classes. For example:
class HasFunctionGroup t where
g :: Int -> t
h :: t -> Int
a :: HasFunctionGroup t => <some type involving t>
a ... = ... g someThing ... h someThingElse
This only works if you can find a type (or multiple types if you use multi-parameter type classes) that the functions have in common, but in cases where it is appropriate it will give you nice idiomatic Haskell.
Couldn't you just pass a function named g to f? As long as g satisfies the interface typeOfSomeParms -> gReturnType, then you should be able to pass in the real function or a mock function.
eg
f g = do
...
g someParams
...
I have not used dependency injection in Java myself, but the texts I have read made it sound a lot like passing higher-order functions, so maybe this will do what you want.
Response to edit: ephemient's answer is better if you need to solve the problem in an enterprisey way, because you define a type containing multiple functions. The prototyping way I propose would just pass a tuple of functions without defining a containing type. But then I hardly ever write type annotations, so refactoring that is not very hard.
A simple solution would be to change your
f x = ...
to
f2 g x = ...
and then
f = f2 g
ftest = f2 gtest
If the functions you depend on are in another module then you could play games with visible module configurations so that either the real module or a mock module is imported.
However I'd like to ask why you feel the need to use mock functions for unit testing anyway. You simply want to demonstrate that the module you are working on does its job. So first prove that your lower level module (the one you want to mock) works, and then build your new module on top of it and demonstrate that works too.
Of course this assumes that you aren't working with monadic values, so it doesn't matter what gets called or with what parameters. In that case you probably need to demonstrate that the right side effects are being invoked at the right time, so monitoring what gets called when is necessary.
Or are you just working to a corporate standard that demands that unit tests only exercise a single module with the whole rest of the system being mocked? That is a very poor way of testing. Far better to build your modules from the bottom up, demonstrating at each level that the modules meet their specs before proceeding to the next level. Quickcheck is your friend here.
You could just have your two function implementations with different names, and g would be a variable that is either defined to be one or the other as you need.
g :: typeOfSomeParms -> gReturnType
g = g_mock -- change this to "g_real" when you need to
g_mock someParms = ... -- mock implementation of g
g_real someParms = ... -- real implementation of g