Is it possible to check if a function is defined, and use it as the Just value of a Maybe type if it is? And use Nothing if it's not defined, of course.
I'm writing a wrapper around atom for use with the TI MSP430 line. Part of what I'm doing is making a function that quickly compiles the code in the right format for MSP430 controllers - for example, compiling an atom to use in a timer interrupt requires a function definition like so:
#pragma vector=TIMERA0_VECTOR __interrupt
void timerAisr(void) {
...
}
At the moment, I have an object that holds references to the function the user would like to use for each different ISR. It looks a bit like this:
mspProgram = MSP430Compilation {
setupFn = Nothing,
setupFnName = "setup",
loopFn = Nothing,
loopFnName = "loop",
timerAISR = Nothing,
timerAISRName = "timerAISR",
And so on. Very configurable - you can choose the name of the function to output in C code, and the Atom to compile for that function. But I've decided I'd like to take more of a convention-over-configuration approach and basically assume some sensible function names. So instead of passing one of these configuration objects, I want the compilation code to check for definitions of sensibly-named functions.
For example, if the user defines an Atom called timerAISR, then my code should compile that atom to a C function named the same, with the appropriate #pragma matter for it to service the timer A interrupt.
So what I need to do is sort of meta-Haskell, checking if the user has defined a function and using that in my library code. I imagine this might involve template Haskell, so I'm off to research it.
EDIT:
I've realised that my original solution was too simplistic once I tried to fit it into my actual code. I hadn't absorbed Haskell's namespacing, so I didn't realise that lookupValueName would not work on values defined in user code. Here's the situation I'm dealing with:
main.hs:
module Main where
import Library
a = 1
main = libraryMain
Library.hs:
{-# LANGUAGE TemplateHaskell #-}
module Library where
import Template
libraryMain :: IO ()
libraryMain = do
$(printSomethingIfIsDefined "a")
$(printSomethingIfIsDefined "b")
Template.hs:
{-# LANGUAGE TemplateHaskell #-}
module Template where
import Language.Haskell.TH
printSomethingIfIsDefined name = do
maybeFn <- lookupValueName name
case maybeFn of
Just fn -> [| putStrLn "It's defined!" |]
Nothing -> [| return () |]
This prints nothing. If I define a in Library.hs, it will print out once, because a is defined in that scope.
Related
I'm writing a sort of scraper or data miner in Haskell. It consists of a main loop and other shared logic, along with a number of "adapters" each of which is designed to scrape a particular type of resource (not only web pages but possibly filesystem objects as well). The adapters all produce the same type of result but I would like them to be independent otherwise. Also, I would like them to share the main loop and other logic.
This is what I have so far, using ExistentialQuantification to hide the adapter affiliation of a scraping job. My idea is that the main loop processes a sequence of jobs, dispatching on the "process" method to find the right adapter implementation.
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ExistentialQuantification #-}
import Control.Monad.Trans.Except
import Data.Text (Text)
import qualified Data.Text as T
-- Metadata about an article
data Article = Article
{ articleSource :: Text
, articleTitle :: Text
, articleUrl :: Text
, articleText :: Text
, articleDate :: Maybe Text
}
deriving (Show)
-- Adapter for scraping a certain type of resource.
--
-- The adapter provides a seed job constructor which samples the current config
-- and creates a seed job to be run first. The seed job then generates all
-- other jobs, e.g. by scraping an index page.
--
--- Each adapter module exports a value of this type, and nothing else.
data Adapter = Adapter
{ adapterName :: Text
, adapterSeedJob :: ScraperConfig -> AnyJob
}
-- Each scrape operation produces zero or more articles, and zero or more
-- new scrape jobs.
type ScrapeResult j = ExceptT AdapterErr IO ([Article], [j])
-- Specification of a resource to be scraped by a certain adapter.
--
-- Each adapter defines its own job type, containing the necessary information.
class ScrapeJob j where
jobAdapter :: j -> Text
jobDesc :: j -> Text
jobProcess :: j -> ScrapeResult j
-- Opaque type encapsulating any adapter's job type, used outside the adapter.
data AnyJob = forall j. ScrapeJob j => AnyJob j
instance ScrapeJob AnyJob where
jobAdapter (AnyJob j) = jobAdapter j
jobDesc (AnyJob j) = jobDesc j
jobProcess (AnyJob j) = wrap <$> jobProcess j
where wrap (as, js) = (as, AnyJob <$> js)
-- Global configuration, such as which passwords to use
data ScraperConfig = ScraperConfig
{ -- ...
}
My problem is that each adapter also has some context attached to it. One example would be that most adapters need to perform some kind of login procedure before it can access any data. I would like this to be handled separately from the scraping itself if possible, but I can't use the trick with AnyJob for "AnyContext" (I think) since there would be no way for the main loop of guaranteeing that the types of the AnyJob and AnyContext match up correctly.
My current ideas, neither of which I'm really satisfied with, are:
Fix the type of the context to a "bag of data" such as Map Text Text and add a special setup method to each adpater which creates this context.
Add the required context as a field of every ScrapeJob instance, and copy it along explicitly whenever a new job is created.
Turn the design upside down, letting each adapter run its own main loop using shared functions defined in a utility module.
Is there something I'm missing here? Any advice on how to improve on this design would be appreciated.
Thanks!
I don't know how to re-assign a variable in a function.
For example,
elephant = 0
function x = elephant = x
Why doesn't this work?
Haskell is a great imperative language, and writing programs that can re-assign state is a really fun advanced topic! This is definitely not the approach you want right now, but come back to it some day 🙂
It takes a bit of effort to define an environment that models global mutable variables. Once you get the hang of it, though, the precision of the types ends up being pretty handy.
We're going to be using the lens and mtl libraries.
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import Control.Monad.State
I'll stick with using integers as your question does, but we'll throw in a type alias to remind ourselves that they are being used as the type of the elephant variable.
type Elephant = Integer
You wanted a program whose global mutable state has an elephant. So first let's define what it means to have an elephant. Lens captures this notion nicely.
class HasElephant a
where
elephant :: Lens' a Elephant
Now we can define function, which assigns a new value to elephant.
function :: (MonadState s m, HasElephant s) => Elephant -> m ()
function x =
elephant .= x
The constraints MonadState s m and HasElephant s are saying our program must be able to hold mutable state of some type s, and the type s must have an elephant.
Let's also define a program that prints the elephant.
printElephant :: (MonadState s m, HasElephant s, MonadIO m) => m ()
printElephant =
use elephant >>= (liftIO . print)
This program does I/O (printing), so we have an additional constraint MonadIO m that says our program type m must be able to do I/O.
The elephant variable is probably only one part of some larger program state. Let's define a data type here to represent the entire state (which we'll name Congo just to be cute because the Congo Basin is one place where elephants live).
data Congo = Congo
{ _congoElephant :: Elephant
}
makeLenses ''Congo
(See Control.Lens.TH for a little bit about makeLenses does here using Template Haskell.)
We must define the way in which the Congo has an elephant.
instance HasElephant Congo
where
elephant = congoElephant
Now we can write an example program. Our program will print the value of elephant, then change the value of elephant, then print it again.
main' :: StateT Congo IO ()
main' =
do
printElephant
function 2
printElephant
Then we can run this program.
main :: IO ()
main = Congo 0 & runStateT main' & void
The output is:
0
2
im trying to re-assign an existing variable
You can't do that in Haskell. You can do something close by using IORefs, but this is very rarely the proper solution to a problem - certainly not in situations a beginner might encounter.
Instead you should re-design your program logic, so that it does not require mutable variables to function.
Haskell is a leader in the functional programming world and functional programming is often called "programming without assignment." It's almost the entire point of functional programming to not use assignment. As soon as you've used it, you're not really doing it in a "functional" way any more. Of course there are times for it, but FP tries to minimize those times.
So, to answer your question, "Why doesn't this work?" First of all the syntax is not correct. = does not mean assignment in Haskell. It binds a name to an expression. You cannot do that twice (in the same scope). In other words, "variables" are immutable (like in math). Second, mutation is a side-effecting action and Haskell treats those as impure actions which must be done in the IO world.
I could show you how to actually mutate a reference in Haskell, but I don't think that's what you need at this point.
The most primitive way to bind a variable x to a value v is to write a function taking x as argument, and pass v to that function.
This can sometimes be used to "simulate" the effect of a mutable variable.
E.g., the imperative code
// sum 0..100
i = s = 0;
while (i <= 100) {
s = s+i;
i++;
}
return s;
becomes
final_s = f 0 0 -- the initial values
where
f i s | i <=100 = f (i+1) (s+i) // increment i, augment s
| otherwise = s // return s at the end
The above code is not pretty FP code, but at least it is close enough to imperative code to make it possible to spot the connections.
A final digression:
When one first notices this, it is usually lured to fall into the Blub paradox. One could easily think: "What!? Haskell needs all that stuff to simulate a simple assignment? If in language Blub assignment is trivial, and simulating that in Haskell requires so much effort, then clearly Blub is much better than Haskell!". And this would be a perfect case of the Blub paradox: when a Blub programmer moves to another language, they immediately perceive what can not be directly translated from Blub, and do not notice all the other features of the new language which were not present in Blub.
Their mind now thinks in "Blub", and it requires a great effort to adapt to new models.
Almost as paradoxically, learning both FP and imperative programming is useful precisely because it's non trivial to learn the other paradigm when used to only one of those. If the step between them were narrow, it would not be worth the effort to learn two close approaches to the same problem.
In general this doesn't work because you usually make immutable declarations, rather than specifying a sequence of operations. You can do:
elephant = 3
main = print elephant
But you can also do:
main = print elephant
elephant = 3
Because the code doesn't specify an order of execution, there is no way to interpret multiple assignments as anything other than an error.
If you want to specify a sequence of operations, use do notation:
main = do
let elephant = 0
print elephant
let elephant = 1
print elephant
let elephant = 2
print elephant
The code in a do block is executed in order, so you can effectively reassign variables the way you can in most programming languages.
Note that this code really just creates a new binding for elephant. The old value still exists:
main = do
let elephant = 1
print elephant
let printElephant = print elephant
let elephant = 2
print elephant
printElephant
Because the printElephant function I define is still using the old value of elephant, this prints:
1
2
1
Can I always expect the single single-quote syntax to desugar to the NameG constructor? e.g. does
'x
always desugar to
(Name (OccName "x") (NameG VarName (PkgName "some-package") (ModName "SomeModule")))
This information must always be there, after name resolution, which is the stage Template Haskell runs after, right? And I haven't been able to quote local names, though I'm only interested in quoting top-level names.
Context: I want to write a function that returns the uniquely-qualified identifier. It's a partial function because I can't constrain the input, as Template Haskell doesn't have any GADTs or anything, while I don't want to wrap the output in uncertainty. And I don't want to use a quasi-quoter or splice, if ' will do. I want to prove that this partial function is safe at runtime when used as above, quoting top-level names in the same module, given:
name (Name occ (NameG _ pkg mod)) = Unique occ pkg mod
I want to have a function like:
(<=>) :: Name -> a -> Named a
given:
data Named a = Named a Unique
to annotate variable bindings:
x = 'x
<=> ...
without the user needing to use the heavy splice syntax $(name ...), and invoke splicing at compile time:
x = $(name 'x)
<=> ...
The user will be writing a lot of these, for configuration.
https://downloads.haskell.org/~ghc/7.8.3/docs/html/users_guide/template-haskell.html and https://hackage.haskell.org/package/template-haskell-2.8.0.0/docs/src/Language-Haskell-TH-Syntax.html#Name didn't say.
(p.s. I'd also like to know if the double single-quote syntax (e.g. ''T) had the analogous guarantee, though I'd expect them to be the same).
Since ' quoted names are known at compile time, why don't you change name to be in the Q monad:
name :: Name -> ExpQ
name (Name occ (NameG _ pkg mod)) = [| Unique occ pkg mod |]
name n = fail $ "invalid name: "++ gshow n
Then you use $(name 'show) :: Unique instead of name 'show :: Unique. If you get an invalid Name (say somebody uses mkName), that failure will show up at compile time.
I have an assignment which is to create a calculator program in Haskell. For example, users will be able to use the calculator by command lines like:
>var cola =5; //define a random variable
>cola*2+1;
(print 11)
>var pepsi = 10
>coca > pepsi;
(print false)
>def coke(x,y) = x+y; //define a random function
>coke(cola,pepsi);
(print 15)
//and actually it's more complicated than above
I have no clue how to program this in Haskell. All I can think of right now is to read the command line as a String, parse it into an array of tokens. Maybe go through the array, detect keywords such "var", "def" then call functions var, def which store variables/functions in a List or something like that. But then how do I store data so that I can use them later in my computation?
Also am I on the right track because I am actually very confused what to do next? :(
*In addition, I am not allowed to use Parsec!*
It looks like you have two distinct kinds of input: declarations (creating new variables and functions) and expressions (calculating things).
You should first define some data structures so you can work out what sort of things you are going to be dealing with. Something like:
data Command = Define Definition | Calculate Expression | Quit
type Name = String
data Definition = DefVar Name Expression | DefFunc Name [Name] Expression
-- ^ alternatively, implement variables as zero-argument functions
-- and merge these cases
data Expression = Var Name | Add Expression Expression | -- ... other stuff
type Environment = [Definition]
To start off with, just parse (tokenise and then parse the tokens, perhaps) the stuff into a Command, and then decide what to do with it.
Expressions are comparatively easy. You assume you already have all the definitions you need (an Environment) and then just look up any variables or do additions or whatever.
Definitions are a bit trickier. Once you've decided what new definition to make, you need to add it to the environment. How exactly you do this depends on how exactly you iterate through the lines, but you'll need to pass the new environment back from the interpreter to the thing which fetches the next line and runs the interpreter on it. Something like:
main :: IO ()
main = mainLoop emptyEnv
where
emptyEnv = []
mainLoop :: Environment -> IO ()
mainLoop env = do
str <- getLine
case parseCommnad str of
Nothing -> do
putStrLn "parse failed!"
mainLoop env
Just Quit -> do
return ()
Just (Define d) -> do
mainLoop (d : env)
Just (Calculate e) -> do
putStrLn (calc env e)
mainLoop env
-- the real meat:
parseCommand :: String -> Maybe Command
calc :: Environment -> Expression -> String -- or Integer or some other appropriate type
calc will need to look stuff up in the environment you create as you go along, so you'll probably also need a function for finding which Definition corresponds to a given Name (or complaining that there isn't one).
Some other decisions you should make:
What do I do when someone tries to redefine a variable?
What if I used one of those variables in the definition of a function? Do I evaluate a function definition when it is created or when it is used?
These questions may affect the design of the above program, but I'll leave it up to you to work out how.
First, you can learn a lot from this tutorial for haskell programming
You need to write your function in another doc with .hs
And you can load the file from you compiler and use all the function you create
For example
plus :: Int -> Int -- that mean the function just work with a number of type int and return Int
plus x y = x + y -- they receive x and y and do the operation
I'd like to be able to take a file with declarations such as:
test_1 = assert $ 1 == 1
test_2 = assert $ 2 == 1
and generate a basic run function like
main = runTests [test_1, test2]
The goal is to get something like Python's nosetest.
Can I do this with template Haskell? I cannot find a lot of documentation on it (there are many broken links in the Wiki).
You might want to look into the test-framework family of packages. In particular, the test-framework-th package provides the Template Haskell function defaultMainGenerator which does exactly what you want for both QuickCheck and HUnit tests, as long as you follow the convention of prefixing HUnit test cases with case_ and QuickCheck properties with prop_.
{-# LANGUAGE TemplateHaskell #-}
import Test.Framework.Providers.HUnit
import Test.Framework.Providers.QuickCheck2
import Test.Framework.TH
import Test.HUnit
import Test.QuickCheck
main = $(defaultMainGenerator)
case_checkThatHUnitWorks =
assert $ 1 == 1
prop_checkThatQuickCheckWorks =
(1 == 1)
There is another way, you don't have to use template haskell. haskell-src-exts can parse Haskell, and you could extract from that.
Or if your purpose is practical, you can make like quickcheck and do a simple-minded parse, i.e. looking for identifiers that start with prop_ in column 0. This is a perfectly adequate solution for real work, though it may be theoretically unsatisfying.