Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I specify types for a function, where they are not used in the function's arguments?

I'm writing some data-access routines, using Persistent. I want my API to be defined in terms of datatypes which represent JSON, but on the persistent side, my datatypes are defined by persistent's templating system.

Given that I have mappings from json to database datatypes, and vice-versa, I thought I should be able to write generalised data access routines.

All was going well until I tried to write the insert function:

standardInsert :: forall d . forall j .
                  (PersistEntityBackend d ~ SqlBackend, PersistEntity d, SimpleJsonDataAccessConversion j d)
               => j -> DatabaseEnvironmentT (Maybe (WithId j))
standardInsert json = do
    maybeId <- runSqlMaybe $ insert db
    return $ toApi <$> maybeId
  where db        = jsonToDataAccess json :: d -- Scoped type variable here.
        toApi key = addId key $ dataAccessToJson db

(j is the type variable for the JSON data type, d is the type variable for the persistent data type).

This function has two type variables, j and d, but only j can be inferred from the arguments.

In other words, if I call standardInsert jsonValue, the type variable d is ambiguous.

I want to call it rather like in C++ - standardInsert<FooJsonType, FooPersistentType>(jsonValue).

How do I tell Haskell what d is? Or am I going about this in completely the wrong way?

like image 859
stusmith Avatar asked Jul 09 '14 21:07

stusmith


People also ask

Can I define a function that accepts no arguments?

You can define a function that doesn't take any arguments, but the parentheses are still required. Both a function definition and a function call must always include parentheses, even if they're empty.

How do you specify data types in a Python function argument?

Python is a strongly-typed dynamic language in which we don't have to specify the data type of the function return value and function argument. It relates type with values instead of names. The only way to specify data of specific types is by providing explicit datatypes while calling the functions.

How do you define a type of function?

The types of functions are defined on the basis of the domain, range, and function expression. The expression used to write the function is the prime defining factor for a function. Along with expression, the relationship between the elements of the domain set and the range set also accounts for the type of function.

Can you specify types in Python?

Python is a dynamically-typed language, which means that we don't have to specify data types when we create variables and functions. While this reduces the amount of code we need to write, the workload that we save is in turn added to the next developer that needs to understand and debug the existing function!


1 Answers

GHC won't be able to infer the type variable d. You need to add it to the type signature itself, by adding a dummy argument. The standard trick is to use a proxy for this dummy argument, which means the caller doesn't need to give an actual value of that type.

You can get Proxy from the tagged package for GHC<7.8, or from base for GHC>=7.8, but for the purposes of the explanation I'll define it explicitly here:

data Proxy a = Proxy

standardInsert :: forall d . forall j .
                  (PersistEntityBackend d ~ SqlBackend,
                   PersistEntity d, SimpleJsonDataAccessConversion j d)
               => Proxy d -> j -> DatabaseEnvironmentT (Maybe (WithId j))
standardInsert _ json = do (...)

and then at a call site:

standardInsert (Proxy :: Proxy FooPersistentType) jsonValue
like image 101
GS - Apologise to Monica Avatar answered Sep 29 '22 09:09

GS - Apologise to Monica