I have been tasked with this:
Write a function enc :: Int -> String -> String that encrypts a string by adding some given integer to each character's Unicode value. Now, using enc as a locally declared function write a function encrypt :: Int -> String -> (String , String -> String) that accepts a String and an Int and returns a pair of an encrypted string and a function with which to decrypt the string.
I have written the function enc, that was fairly easy, but I cannot figure out how to return a function from encrypt.
So far I have
encrypt :: Int -> String -> (String , String -> String)
encrypt num word = (enc num word, ???)
I have no idea what to write in place of '???'. I've read a fair bit about curried functions but everything I've found defines a function that takes a function as a parameter and uses that function to recursively call itself. encrypt doesn't take a function as a parameter. How can I define an entirely new function and return it, rather than returning its value, all from within another function?
There's the explicit lambda approach that declares a function with a parameter:
-- Expression is of the type String -> String
-- Similar to python lambda mystring: enc(-num, mystring)
-- or java (mystring) => enc(-num, mystring)
\mystring -> enc (-num) mystring
However, thanks to currying, you can just take enc :: Int -> String -> String and give it an int, which will result in a String -> String:
-- Also of the type String -> String
enc (-num)
A lambda expression would be the most direct way, as others pointed out. Note that you can still simply define your own function and return it, e.g.
encrypt :: Int -> String -> (String , String -> String)
encrypt num word = (enc num word, myFunction)
where
myFunction :: String -> String
myFunction str = .... -- here you can use num, word, str to produce the result you need
Related
I want to pass a function a wildcard or any type or even a way to choose between either of multiple types rather than just restrict it to String, or Number, or Boolean, for example:
myFunction :: a -> String
or
myFunction :: _ -> String
or
myFunction :: (String || Number) -> String
Is that possible?
myFunction :: a -> String is technically possible, however it's profoundly useless – since this must be able to deal with an argument of any type, there's nothing you can actually do with the argument. (It's a bit like getting a can with a completely unspecified substance – you wouldn't eat it in case it's corrosive, you couldn't use it for cleaning purposes in case it's fat, paint or glue, you couldn't process it further... in case of an unrestricted Haskell type you couldn't even analyse it.)
If you narrow it down to types that support some kind of common operation, a polymorphic argument can make sense:
myFunction' :: Show a => a -> String
myFunction' x = "The value is " ++ show x
Your other approach, supporting only two very specific types, is also possible:
myFunction'' :: Either String Integer -> String
myFunction'' (Left s) = "Got a string: “" ++ s ++ "”"
myFunction'' (Right n) = "Got a number: " ++ show n
Note that these two approaches are quite different: Show a => a -> String can be used as String -> String or as Integer -> String, or in fact any other type which supports the show operation (including newly-defined types of your own), but you must decide at compile-time which type you want. At runtime, all arguments passed to this function must then have the same type.
Either String Integer -> String can accept a mixture of String- and Integer values at runtime, but is always restricted to only these two types.
Defining a function a -> String is easily possible, it just won't be able to do anything useful unless you also restrict a to some typeclass (like Show).
_ -> String is not valid syntax. If it were, I imagine it would do the same as a -> String, so you can just use that.
(String || Number) -> String is also not valid syntax, but Either String Number -> String is. You can also define your data type with constructors for the types you want to allow.
myFunction :: a -> String means that myFunction can take an argument of any type, but will always return a string. This is legal Haskell syntax.
With PartialTypeSignatures enabled, myFunction :: _ -> String is legal Haskell syntax, with _ acting as a "hole", or a way to get the compiler to tell you what type it inferred at that position:
Temp.hs:4:15: warning: [-Wpartial-type-signatures]
• Found type wildcard ‘_’ standing for ‘String’
• In the type signature: myFunction :: _ -> String
|
4 | myFunction :: _ -> String
| ^
If you enable TypeOperators, then you can define type (||) = Either, which make myFuncion :: (String || Number) -> String mean that myFuncion is a function that takes an argument of type Either String Number and returns a String:
type Number = Integer
type (||) = Either
myFuncion = (String || Number) -> String
myFuncion (Left string) = string
myFuncion (Right number) = show number
As I was working through cis 194 (week 5) I came across a problem that introduced two new concepts to me at once, and I'm having difficulty making it, at the very least, output the correct type.
My goal is to implement var in the instance declared at the bottom, however, I have never used an instance that was a function before, and nor have I used Data.Map, so I'm not very clear on what my solution syntax should even look like.
{-# LANGUAGE FlexibleInstances #-}
import qualified Data.Map as M
class HasVars a where
var :: String -> a
-- | This instance allows variables to be interpreted as functions from a
-- mapping of variables to Integer values to (possibly) Integer values
instance HasVars (M.Map String Integer -> Maybe Integer) where
-- not sure how to implement var here
So when you have
class HasVars a where
var :: String -> a
That means that, for any instance a, you have a function var :: String -> a.
So, if Map String Integer -> Maybe Integer is an instance, then that means that you have to provide a function:
var :: String -> (Map String Integer -> Maybe Integer)
Remember that (->) associates from the right, so the parentheses here are optional --
var :: String -> Map String Integer -> Maybe Integer
So, var is a function that takes a String and a Map and returns a Maybe Integer. Let's write it!
instance HasVars (Map String Integer -> Maybe Integer) where
-- var :: String -> Map String Integer -> Maybe Integer
var str mp = M.lookup str mp
And this works!
edit: Question in answer
I see that you're wondering why
var str = M.lookup str
works. Remember that M.lookup str doesn't return a Maybe Integer. It returns a Map String Integer -> Maybe Integer. Which is exactly what a should be...exactly what you want. var str is now a function that takes a map and returns a Maybe Integer.
M.lookup str doesn't have a map, yes, so it can't return a Maybe Integer. But it's a Map String Integer -> Maybe Integer. So var "hello" is now a Map String Integer -> Maybe Integer. var "hello" gives you a function that takes a map and returns a Maybe Integer. So if you give var "hello" a map, like var "hello" mp, then you get a Maybe Integer :D
So, I've come up with something that at the very least compiles. I had unnecessarily caused myself some confusion when I was attempting to solve this by repeatedly using Maybe as a constructor, and staring blankly at the error message that it wasn't defined. Just is the constructor for Maybe, Maybe isn't a constructor; too many times...
Secondly, I completely blanked by using lookup ... instead of M.lookup ..., leading to unexpected type results.
Those stumblings aside, here's what I tried
instance HasVars (M.Map String Integer -> Maybe Integer) where
var str = M.lookup str -- can be Eta-reduced
This compiles, but what doesn't make too much sense to me is that per the instance declaration, shouldn't I be providing a key-value Map? M.lookup will give back a Maybe Integer, but it just doesn't seem like I've given it enough to do that, because it needs a key and a Map, and I don't seem to have a Map. Perhaps my understanding of how class instances work is off.
I have a list of strings:
[" ix = index"," ctr = counter"," tbl = table"]
and I want to create a tuple from it like:
[("ix","index"),("ctr","counter"),("tbl","table")]
I even tried:
genTuple [] = []
genTuples (a:as)= do
i<-splitOn '=' a
genTuples as
return i
Any help would be appriciated
Thank you.
Haskell's type system is really expressive, so I suggest to think about the problem in terms of types. The advantage of this is that you can solve the problem 'top-down' and the whole program can be typechecked as you go, so you can catch all kinds of errors early on. The general approach is to incrementally divide the problem into smaller functions, each of which remaining undefined initially but with some plausible type.
What you want is a function (let's call it convert) which take a list of strings and generates a list of tuples, i.e.
convert :: [String] -> [(String, String)]
convert = undefined
It's clear that each string in the input list will need to be parsed into a 2-tuple of strings. However, it's possible that the parsing can fail - the sheer type String makes no guarantees that your input string is well formed. So your parse function maybe returns a tuple. We get:
parse :: String -> Maybe (String, String)
parse = undefined
We can immediately plug this into our convert function using mapMaybe:
convert :: [String] -> [(String, String)]
convert list = mapMaybe parse list
So far, so good - but parse is literally still undefined. Let's say that it should first verify that the input string is 'valid', and if it is - it splits it. So we'll need
valid :: String -> Bool
valid = undefined
split :: String -> (String, String)
split = undefined
Now we can define parse:
parse :: String -> Maybe (String, String)
parse s | valid s = Just (split s)
| otherwise = Nothing
What makes a string valid? Let's say it has to contain a = sign:
valid :: String -> Bool
valid s = '=' `elem` s
For splitting, we'll take all the characters up to the first = for the first tuple element, and the rest for the second. However, you probably want to trim leading/trailing whitespace as well, so we'll need another function. For now, let's make it a no-op
trim :: String -> String
trim = id
Using this, we can finally define
split :: String -> (String, String)
split s = (trim a, trim (tail b))
where
(a, b) = span (/= '=') s
Note that we can safely call tail here because we know that b is never empty because there's always a separator (that's what valid verified). Type-wise, it would've been nice to express this guarantee using a "non-empty string" but that may be a bit overengineered. :-)
Now, there are a lot of solutions to the problem, this is just one example (and there are ways to shorten the code using eta reduction or existing libraries). The main point I'm trying to get across is that Haskell's type system allows you to approach the problem in a way which is directed by types, which means the compiler helps you fleshing out a solution from the very beginning.
You can do it like this:
import Control.Monda
import Data.List
import Data.List.Split
map ((\[a,b] -> (a,b)) . splitOn "=" . filter (/=' ')) [" ix = index"," ctr = counter"," tbl = table"]
The map function works fine on really easy functions that take no arguments like *7 to every element in a list of Ints.
But say I made a custom function that takes a Char, String and Int and then returns a Char and I wanted to apply this function to a list of Chars i.e. a String to get a String back after applying the other function to each Char? When I try this all I get is error messages?
Put your Char argument to the last position:
foo :: String -> Int -> Char -> Char
foo str num c = c
bar = map (foo str num)
But we really need some more information from your side to help you better. Can you add the code you tried to write to your question?
I have a very simple question: Given a function accepting a char and returning a string
test :: Char -> [String]
how can one convert the char into a string? I'm confused over the two types.
In Haskell String is an alias for [Char]:
type String = [Char]
If you just want a function that converts a single char to a string you could e.g. do
charToString :: Char -> String
charToString c = [c]
If you prefer pointfree style you could also write
charToString :: Char -> String
charToString = (:[])
A String is just a [Char]
But that's just a nice way of saying
'H':'E':'L':'L':'O':[]
So to make it a [String] we could do:
['H':'E':'L':'L':'O':[]]
Another way would be using
return . return
Since return for lists is defined as :[]
Note that you can convert any type implementing the Show type class to a string using show:
(Show a) => a -> String
Because Char implements this, the function is already written for you!