I'm trying to redo all of my Haskell homework problems using Erlang, and one thing that gets me is how to use a list of functions that don't have all of their parameters.
Example: I'm trying to use this fold, but I don't know how to pass in the functions so that it operates on the accumulator
%%inside my module)
add(X,Y) -> X + Y.
multiply(X,Y) -> X*Y.
Afterwards using this in the command line:
lists:foldl(fun(Function,Accumulator) -> Function(Accumulator) end, 3, [add(3),multiply(5)]).
In Erlang you must call function passing all parameters it requires. But you can easily avoid it by creating an anonymous function which takes only those parameters you need and then calls your function rightly. If you need a function which takes one parameter X and calls function add(3, X) you can create an anonymous function like that:
fun (X) -> add(3, X) end
This is an example for your task:
lists:foldl(fun (Function, Accumulator) -> Function(Accumulator) end, 3,
[fun (X) -> add(3, X) end, fun (X) -> multiply(5, X) end]).
In terms of native Erlang there is not any form of partial evaluation like you want. You will have to create your own fun's to do it. However if you use the Erlando Monad Library then you can use pattern matching to create it. It works by the fact that the erlang compiler lets you play with the AST on compiling code so you can do cool stuff like this.
One can fairly easily write a partial application function which is called analogous way to erlang:apply/3. It lacks the elegance you have in languages that support currying.
-module(partial).
-export([apply/4]).
apply(Module, Name, Arity, Args) when length(Args) < Arity ->
Left = Arity - length(Args),
fun(Args1) when length(Args1) < Left ->
fun(Args2) ->
apply(Module, Name, Arity, Args2 ++ Args1 ++ Args)
end;
(Args1) when length(Args1) > Left ->
erlang:error(badarg);
(Args1) ->
erlang:apply(Module, Name, Args1 ++ Args)
end;
apply(_, _, Arity, Args) when length(Args) > Arity ->
erlang:error(badarg);
apply(Module, Name, _, Args) ->
erlang:apply(Module, Name, Args).
-module(f).
-export([curry/1]).
curry(AnonymousFun) ->
{arity, Arity} =
erlang:fun_info(AnonymousFun, arity),
do_curry(AnonymousFun, Arity, [[], [], []]).
do_curry(Fun, 0, [Fronts, Middle, Ends] = X) ->
% Fronts ++ Middle ++ ")" ++ Ends;
[F, M, E] =
lists:map(fun(L) -> string:join(L, "") end, X),
Fstring =
F ++ "Run(" ++ string:trim(M, trailing, ",") ++ ")" ++ E,
{ok, Tokens, _} =
erl_scan:string(Fstring ++ "."),
{ok, Parsed} =
erl_parse:parse_exprs(Tokens),
FunBinding =
erl_eval:add_binding(
'Run',
Fun,
erl_eval:new_bindings()
),
{value ,CurriedFun, _} =
erl_eval:exprs(Parsed, FunBinding),
CurriedFun;
do_curry(Fun, Arity, [Fronts, Middle, Ends]) ->
VarName = [64 + Arity],
NewFronts = ["fun(" ++ VarName ++ ") -> " | Fronts] ,
NewMiddle = [VarName ++ ","|Middle],
NewEnds = [" end"|Ends],
do_curry(Fun, Arity-1, [NewFronts, NewMiddle, NewEnds]).
Usage (noise culled from shell output):
72> c("./f") % If `f.erl` is in the current dir that is.
73> F = f:curry(fun(A,B,C) -> A + B + C end).
74> F(1).
75> G = F(1).
76> G(2).
77> H = G(2).
78> H(3).
6
79> I = (F(1))(2).
80> I(3).
6
82> F2 = mtest:curry(fun erlang:'++'/2).
83> F2("lofa").
84> (F2("lofa"))("miez").
"lofamiez"
85> ((f:curry(fun lists:map/2))((f:curry(fun filename:join/2))("dir")))(["a_file", "b_file"]).
["dir/a_file","dir/b_file"]
Useful resources:
http://erlang.org/pipermail/erlang-questions/2005-April/015279.html
https://grantwinney.com/how-to-evaluate-a-string-of-code-in-erlang-at-runtime/
Convert erlang terms to string, or decode erlang binary
Erlang trying to evaluate a string
Knowing the number of parameters of a passed function (erlang)
https://erlang.org/doc/man/erl_eval.html
lists:foldl(
fun(Function,Accumulator) -> Function(Accumulator) end,
3,
[
fun(X) -> modname:add(3, X) end,
fun(X) -> modname:multiply(5, X) end
]
).
Related
I am trying to write a function which outputs all variable names. When used on the example below, the output should be
*Main> used example
["a","b","x","y"]
This is what I have written so far...
import Data.Char
import Data.List
type Var = String
data Term =
Variable Var
| Lambda Var Term
| Apply Term Term
-- deriving Show
instance Show Term where
show = pretty
example :: Term
example = Lambda "a" (Lambda "x" (Apply (Apply (Lambda "y" (Variable "a")) (Variable "x")) (Variable "b")))
pretty :: Term -> String
pretty = f 0
where
f i (Variable x) = x
f i (Lambda x m) = if i /= 0 then "(" ++ s ++ ")" else s where s = "\\" ++ x ++ ". " ++ f 0 m
f i (Apply n m) = if i == 2 then "(" ++ s ++ ")" else s where s = f 1 n ++ " " ++ f 2 m
used :: Term -> [Var]
used (Variable n) = [n]
used (Lambda n t) = "\\" ++ n ++ ". " ++ used t
used (Apply t1 t2) = used t1 ++ used t2
The problem lies in the line used (Lambda n t) = "\\" ++ n ++ ". " ++ used t, I get this error message:
list.hs:28:47: error:
lexical error in string/character literal at character '\n'
|
28 | used (Lambda n t) = "\" ++ n ++ ". " ++ used t
Why am I getting this complaint?
You are copying and pasting from examples too much. Keep thinking about what the function is supposed to mean as you are writing it.
used (Variable n) = [n]
This is correct: the set of variables used in a term which is just a variable is the variable used. For example, the set of variables used in the term x is just [x].
used (Apply t1 t2) = used t1 ++ used t2
This is also correct1: the set of variables used in say (x y z) (w x y) is the union of the variables used in x y z and in w x y: that is [x,y,z,w,x,y].
So now let's consider the case you are struggling with.
used (Lambda n t) = ...
The code you have seems to be attempting to print the the term into a string, which is not what we are trying to do here -- we are trying to find the set of used variables.
Let's consider an example: we have a term like (\x. x y z), and we want to find out what its used variables are. Before trying to come up with the general solution, ask yourself what the result should be in this example.
If this function is going to be nicely recursive, can we express your expected result in terms of the used variables of x y z? How do we transform the set of used variables of x y z into the set of used variables of \x. x y z?
1 Though you might get duplicates.
I'm trying to implement a function which converts a string to a list of Maybe Ints, e.g. readInts "1 2 42 foo" = [Just 1,Just 2,Just 42,Nothing].
My first aproach was:
readInts (s::String) = do {
ws <- words s;
return (map (readMaybe::(String -> Maybe Int)) ws)
}
This resulted in the following error:
lab_monad.hs:20:52:
Couldn't match type ‘Char’ with ‘[Char]’
Expected type: [String]
Actual type: String
In the second argument of ‘map’, namely ‘ws’
In the first argument of ‘return’, namely
‘(map (readMaybe :: String -> Maybe Int) ws)’
Failed, modules loaded: none.
What I tried next (and worked), was:
readInts (s::String) = do {
let ws = (words s) in do
return (map (readMaybe::(String -> Maybe Int)) ws)
}
My question here is, words s obviously is of type [String]. Why does the interpreter say it is a String? What am I not understanding about <- operator?
ws <- words s, in the list monad, nondeterministically assigns one word from words s to ws; the remaining code simply works with that one word, and the return function "magically" combines the results of working on all the words into the result list.
readInts s = do
ws <- words s -- ws represents *each* word in words s
return (readMaybe ws)
The do notation is just syntactic sugar for using monadic bind:
readInts s = words s >>= (\ws -> return (readMaybe ws))
Without using the Monad instance for lists, you can use map to apply the same function to each word.
readInts s = map readMaybe (words s)
let, on the other hand, simply provides a name for a more complicated expression to be used in another expression. It can be considered syntactic sugar for defining and immediately applying an anonymous function. That is,
let x = y + z in f x
is equivalent to
(\x -> f x) (y + z)
^ ^ ^
| | |
| | RHS of let binding
| part after "in"
LHS of let binding
A let statement with multiple bindings is equivalent to nested let statements:
let x = y + z
a = b + c
in x + a
is equivalent to
let x = y + z
in let a = b + c
in x + a
which desugars to
(\x -> (\a -> x + a)(b + c))(y + z)
I'm learning do expression and Monad using LEARN YOU A HASKELL FOR GREAT GOOD. There's a gcd implementation using tell function makes me confused.
gcd :: Int -> Int -> Writer [String] Int
gcd a b
| b == 0 = tell ["Finished with " ++ show a ] >>= (\_ -> return a)
| otherwise = tell [show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b)] >>= (\_ -> gcd b (a `mod` b))
gcdResult = gcd 8 3
-- result: WriterT (Identity (1,["8 mod 3 = 2","3 mod 2 = 1","2 mod 1 = 0","Finished with 1"]))
But I am confused by the tell function. When using >>= (\_ -> ...) or >>, the result before will be ignored, so why does the result of tell can be passed to the final result? As my thought, the tell result may be ignored, and the final result will be WriterT (Identity (1,[])).
You're confusing the result with the context. You are correct that, when applying >> or >>= \_ ->, the result of the left-hand-side is ignored. However, if the entire value was ignored, it would be completely pointless; the monadic context can be passed forward.
a >> b
This means "take the context from a and combine it with the context of b, keeping the result value of b". In the case of Writer, the monadic context is that there is some write-only data being passed about.
tell :: Monoid w => w -> Writer w ()
This is the (somewhat simplified) type of tell. It takes a value to write and returns a Writer instance whose result value is insignificant (()) but whose context is that there is a write-only value containing the w argument. When you apply >>, the result value is ignored (which is irrelevant because tell returns nothing of value through its result) but the context is kept.
I use System.Random and System.Random.Shuffle to shuffle the order of characters in a string, I shuffle it using:
shuffle' string (length string) g
g being a getStdGen.
Now the problem is that the shuffle can result in an order that's identical to the original order, resulting in a string that isn't really shuffled, so when this happens I want to just shuffle it recursively until it hits a a shuffled string that's not the original string (which should usually happen on the first or second try), but this means I need to create a new random number generator on each recursion so it wont just shuffle it exactly the same way every time.
But how do I do that? Defining a
newg = newStdGen
in "where", and using it results in:
Jumble.hs:20:14:
Could not deduce (RandomGen (IO StdGen))
arising from a use of shuffle'
from the context (Eq a)
bound by the inferred type of
shuffleString :: Eq a => IO StdGen -> [a] -> [a]
at Jumble.hs:(15,1)-(22,18)
Possible fix:
add an instance declaration for (RandomGen (IO StdGen))
In the expression: shuffle' string (length string) g
In an equation for `shuffled':
shuffled = shuffle' string (length string) g
In an equation for `shuffleString':
shuffleString g string
= if shuffled == original then
shuffleString newg shuffled
else
shuffled
where
shuffled = shuffle' string (length string) g
original = string
newg = newStdGen
Jumble.hs:38:30:
Couldn't match expected type `IO StdGen' with actual type `StdGen'
In the first argument of `jumble', namely `g'
In the first argument of `map', namely `(jumble g)'
In the expression: (map (jumble g) word_list)
I'm very new to Haskell and functional programming in general and have only learned the basics, one thing that might be relevant which I don't know yet is the difference between "x = value", "x <- value", and "let x = value".
Complete code:
import System.Random
import System.Random.Shuffle
middle :: [Char] -> [Char]
middle word
| length word >= 4 = (init (tail word))
| otherwise = word
shuffleString g string =
if shuffled == original
then shuffleString g shuffled
else shuffled
where
shuffled = shuffle' string (length string) g
original = string
jumble g word
| length word >= 4 = h ++ m ++ l
| otherwise = word
where
h = [(head word)]
m = (shuffleString g (middle word))
l = [(last word)]
main = do
g <- getStdGen
putStrLn "Hello, what would you like to jumble?"
text <- getLine
-- let text = "Example text"
let word_list = words text
let jumbled = (map (jumble g) word_list)
let output = unwords jumbled
putStrLn output
This is pretty simple, you know that g has type StdGen, which is an instance of the RandomGen typeclass. The RandomGen typeclass has the functions next :: g -> (Int, g), genRange :: g -> (Int, Int), and split :: g -> (g, g). Two of these functions return a new random generator, namely next and split. For your purposes, you can use either quite easily to get a new generator, but I would just recommend using next for simplicity. You could rewrite your shuffleString function to something like
shuffleString :: RandomGen g => g -> String -> String
shuffleString g string =
if shuffled == original
then shuffleString (snd $ next g) shuffled
else shuffled
where
shuffled = shuffle' string (length string) g
original = string
End of answer to this question
One thing that might be relevant which I don't know yet is the difference between "x = value", "x <- value", and "let x = value".
These three different forms of assignment are used in different contexts. At the top level of your code, you can define functions and values using the simple x = value syntax. These statements are not being "executed" inside any context other than the current module, and most people would find it pedantic to have to write
module Main where
let main :: IO ()
main = do
putStrLn "Hello, World"
putStrLn "Exiting now"
since there isn't any ambiguity at this level. It also helps to delimit this context since it is only at the top level that you can declare data types, type aliases, and type classes, these can not be declared inside functions.
The second form, let x = value, actually comes in two variants, the let x = value in <expr> inside pure functions, and simply let x = value inside monadic functions (do notation). For example:
myFunc :: Int -> Int
myFunc x =
let y = x + 2
z = y * y
in z * z
Lets you store intermediate results, so you get a faster execution than
myFuncBad :: Int -> Int
myFuncBad x = (x + 2) * (x + 2) * (x + 2) * (x + 2)
But the former is also equivalent to
myFunc :: Int -> Int
myFunc x = z * z
where
y = x + 2
z = y * y
There are subtle difference between let ... in ... and where ..., but you don't need to worry about it at this point, other than the following is only possible using let ... in ..., not where ...:
myFunc x = (\y -> let z = y * y in z * z) (x + 2)
The let ... syntax (without the in ...) is used only in monadic do notation to perform much the same purpose, but usually using values bound inside it:
something :: IO Int
something = do
putStr "Enter an int: "
x <- getLine
let y = myFunc (read x)
return (y * y)
This simply allows y to be available to all proceeding statements in the function, and the in ... part is not needed because it's not ambiguous at this point.
The final form of x <- value is used especially in monadic do notation, and is specifically for extracting a value out of its monadic context. That may sound complicated, so here's a simple example. Take the function getLine. It has the type IO String, meaning it performs an IO action that returns a String. The types IO String and String are not the same, you can't call length getLine, because length doesn't work for IO String, but it does for String. However, we frequently want that String value inside the IO context, without having to worry about it being wrapped in the IO monad. This is what the <- is for. In this function
main = do
line <- getLine
print (length line)
getLine still has the type IO String, but line now has the type String, and can be fed into functions that expect a String. Whenever you see x <- something, the something is a monadic context, and x is the value being extracted from that context.
So why does Haskell have so many different ways of defining values? It all comes down to its type system, which tries really hard to ensure that you can't accidentally launch the missiles, or corrupt a file system, or do something you didn't really intend to do. It also helps to visually separate what is an action, and what is a computation in source code, so that at a glance you can tell if an action is being performed or not. It does take a while to get used to, and there are probably valid arguments that it could be simplified, but changing anything would also break backwards compatibility.
And that concludes today's episode of Way Too Much Information(tm)
(Note: To other readers, if I've said something incorrect or potentially misleading, please feel free to edit or leave a comment pointing out the mistake. I don't pretend to be perfect in my descriptions of Haskell syntax.)
Here is my first Haskell program. What parts would you write in a better way?
-- Multiplication table
-- Returns n*n multiplication table in base b
import Text.Printf
import Data.List
import Data.Char
-- Returns n*n multiplication table in base b
mulTable :: Int -> Int -> String
mulTable n b = foldl (++) (verticalHeader n b w) (map (line n b w) [0..n])
where
lo = 2* (logBase (fromIntegral b) (fromIntegral n))
w = 1+fromInteger (floor lo)
verticalHeader :: Int -> Int -> Int -> String
verticalHeader n b w = (foldl (++) tableHeader columnHeaders)
++ "\n"
++ minusSignLine
++ "\n"
where
tableHeader = replicate (w+2) ' '
columnHeaders = map (horizontalHeader b w) [0..n]
minusSignLine = concat ( replicate ((w+1)* (n+2)) "-" )
horizontalHeader :: Int -> Int -> Int -> String
horizontalHeader b w i = format i b w
line :: Int -> Int -> Int -> Int -> String
line n b w y = (foldl (++) ((format y b w) ++ "|" )
(map (element b w y) [0..n])) ++ "\n"
element :: Int -> Int -> Int -> Int -> String
element b w y x = format (y * x) b w
toBase :: Int -> Int -> [Int]
toBase b v = toBase' [] v where
toBase' a 0 = a
toBase' a v = toBase' (r:a) q where (q,r) = v `divMod` b
toAlphaDigits :: [Int] -> String
toAlphaDigits = map convert where
convert n | n < 10 = chr (n + ord '0')
| otherwise = chr (n + ord 'a' - 10)
format :: Int -> Int -> Int -> String
format v b w = concat spaces ++ digits ++ " "
where
digits = if v == 0
then "0"
else toAlphaDigits ( toBase b v )
l = length digits
spaceCount = if (l > w) then 0 else (w-l)
spaces = replicate spaceCount " "
Here are some suggestions:
To make the tabularity of the computation more obvious, I would pass the list [0..n] to the line function rather than passing n.
I would further split out the computation of the horizontal and vertical axes so that they are passed as arguments to mulTable rather than computed there.
Haskell is higher-order, and almost none of the computation has to do with multiplication. So I would change the name of mulTable to binopTable and pass the actual multiplication in as a parameter.
Finally, the formatting of individual numbers is repetitious. Why not pass \x -> format x b w as a parameter, eliminating the need for b and w?
The net effect of the changes I am suggesting is that you build a general higher-order function for creating tables for binary operators. Its type becomes something like
binopTable :: (i -> String) -> (i -> i -> i) -> [i] -> [i] -> String
and you wind up with a much more reusable function—for example, Boolean truth tables should be a piece of cake.
Higher-order and reusable is the Haskell Way.
You don't use anything from import Text.Printf.
Stylistically, you use more parentheses than necessary. Haskellers tend to find code more readable when it's cleaned of extraneous stuff like that. Instead of something like h x = f (g x), write h = f . g.
Nothing here really requires Int; (Integral a) => a ought to do.
foldl (++) x xs == concat $ x : xs: I trust the built-in concat to work better than your implementation.
Also, you should prefer foldr when the function is lazy in its second argument, as (++) is – because Haskell is lazy, this reduces stack space (and also works on infinite lists).
Also, unwords and unlines are shortcuts for intercalate " " and concat . map (++ "\n") respectively, i.e. "join with spaces" and "join with newlines (plus trailing newline)"; you can replace a couple things by those.
Unless you use big numbers, w = length $ takeWhile (<= n) $ iterate (* b) 1 is probably faster. Or, in the case of a lazy programmer, let w = length $ toBase b n.
concat ( (replicate ((w+1)* (n+2)) "-" ) == replicate ((w+1) * (n+2)) '-' – not sure how you missed this one, you got it right just a couple lines up.
You do the same thing with concat spaces, too. However, wouldn't it be easier to actually use the Text.Printf import and write printf "%*s " w digits?
Norman Ramsey gave excellent high-level (design) suggestions; Below are some low-level ones:
First, consult with HLint. HLint is a friendly program that gives you rudimentary advice on how to improve your Haskell code!
In your case HLint gives 7 suggestions. (mostly about redundant brackets)
Modify your code according to HLint's suggestions until it likes what you feed it.
More HLint-like stuff:
concat (replicate i "-"). Why not replicate i '-'?
Consult with Hoogle whenever there is reason to believe that a function you need is already available in Haskell's libraries. Haskell comes with tons of useful functions so Hoogle should come in handy quite often.
Need to concatenate strings? Search for [String] -> String, and voila you found concat. Now go replace all those folds.
The previous search also suggested unlines. Actually, this even better suits your needs. It's magic!
Optional: pause and thank in your heart to Neil M for making Hoogle and HLint, and thank others for making other good stuff like Haskell, bridges, tennis balls, and sanitation.
Now, for every function that takes several arguments of the same type, make it clear which means what, by giving them descriptive names. This is better than comments, but you can still use both.
So
-- Returns n*n multiplication table in base b
mulTable :: Int -> Int -> String
mulTable n b =
becomes
mulTable :: Int -> Int -> String
mulTable size base =
To soften the extra characters blow of the previous suggestion: When a function is only used once, and is not very useful by itself, put it inside its caller's scope in its where clause, where it could use the callers' variables, saving you the need to pass everything to it.
So
line :: Int -> Int -> Int -> Int -> String
line n b w y =
concat
$ format y b w
: "|"
: map (element b w y) [0 .. n]
element :: Int -> Int -> Int -> Int -> String
element b w y x = format (y * x) b w
becomes
line :: Int -> Int -> Int -> Int -> String
line n b w y =
concat
$ format y b w
: "|"
: map element [0 .. n]
where
element x = format (y * x) b w
You can even move line into mulTable's where clause; imho, you should.
If you find a where clause nested inside another where clause troubling, then I suggest to change your indentation habits. My recommendation is to use consistent indentation of always 2 or always 4 spaces. Then you can easily see, everywhere, where the where in the other where is at. ok
Below's what it looks like (with a few other changes in style):
import Data.List
import Data.Char
mulTable :: Int -> Int -> String
mulTable size base =
unlines $
[ vertHeaders
, minusSignsLine
] ++ map line [0 .. size]
where
vertHeaders =
concat
$ replicate (cellWidth + 2) ' '
: map horizontalHeader [0 .. size]
horizontalHeader i = format i base cellWidth
minusSignsLine = replicate ((cellWidth + 1) * (size + 2)) '-'
cellWidth = length $ toBase base (size * size)
line y =
concat
$ format y base cellWidth
: "|"
: map element [0 .. size]
where
element x = format (y * x) base cellWidth
toBase :: Integral i => i -> i -> [i]
toBase base
= reverse
. map (`mod` base)
. takeWhile (> 0)
. iterate (`div` base)
toAlphaDigit :: Int -> Char
toAlphaDigit n
| n < 10 = chr (n + ord '0')
| otherwise = chr (n + ord 'a' - 10)
format :: Int -> Int -> Int -> String
format v b w =
spaces ++ digits ++ " "
where
digits
| v == 0 = "0"
| otherwise = map toAlphaDigit (toBase b v)
spaces = replicate (w - length digits) ' '
0) add a main function :-) at least rudimentary
import System.Environment (getArgs)
import Control.Monad (liftM)
main :: IO ()
main = do
args <- liftM (map read) $ getArgs
case args of
(n:b:_) -> putStrLn $ mulTable n b
_ -> putStrLn "usage: nntable n base"
1) run ghc or runhaskell with -Wall; run through hlint.
While hlint doesn't suggest anything special here (only some redundant brackets), ghc will tell you that you don't actually need Text.Printf here...
2) try running it with base = 1 or base = 0 or base = -1
If you want multiline comments use:
{- A multiline
comment -}
Also, never use foldl, use foldl' instead, in cases where you are dealing with large lists which must be folded. It is more memory efficient.
A brief comments saying what each function does, its arguments and return value, is always good. I had to read the code pretty carefully to fully make sense of it.
Some would say if you do that, explicit type signatures may not be required. That's an aesthetic question, I don't have a strong opinion on it.
One minor caveat: if you do remove the type signatures, you'll automatically get the polymorphic Integral support ephemient mentioned, but you will still need one around toAlphaDigits because of the infamous "monomorphism restriction."