Strict type alias in Haskell - haskell

Suppose I have a recursive function taking 3 integers, each having a different meaning, e.g.
func :: Int -> Int -> Int -> SomeType1 -> SomeType2
What I want is to prevent myself from mistyping the order of the arguments like this (somewhere in the func implementation):
func a b c t = f b a c ( someProcessing t )
The easiest way I've come up with is to define type aliases like
type FuncFirstArg = Int
type FuncSecondArg = Int
type FuncThirdArg = Int
And change func signature:
func :: FuncFirstArg -> FuncSecondArg -> FuncThirdArg -> SomeType1 -> SomeType2
But it seems like this approach doesn't work as I intended. Why does Haskell still allow me to pass FuncSecondArg as a first argument and so on. Is there a way to do what I want without declaring datatypes?

type in Haskell is a rename of an existing type. Just like String and [Char] are fully exchangeable, so are FuncFirstArg and Int, and by transition FuncSecondArg as well.
The most normal solution is to use a newtype which was introduced exactly for the purpose of what you try to achieve. For convenience, it is good to declare it as a record:
newtype FuncFirstArg = FuncFirstArg {unFuncFirstArg :: Int}
Note that newtype is entirely reduced during compilation time, so it has no overhead on the runtime.
However, if you have many arguments like in your example, a common strategy is to create a dedicated type for all of the parameters supplied to the function:
data FuncArgs = FuncArgs
{ funcA :: Int
, funcB :: Int
, funcC :: Int
, funcT :: Sometype1
}
f :: FuncArgs -> Sometype2
Yes, it has some bad impact on currying and partial application, but in many cases you can deal with it by providing predefined argument packs or even uncurry the function:
defaultArgs :: Sometype1 -> FuncArgs
defaultArgs t = FuncArgs {a = 0, b = 0, c = 0, t = t}
fUnc :: Int -> Int -> Int -> SomeType1 -> SomeType2
fUnc a b c t = f $ FuncArgs a b c t
Conclusion
For the typechecker to distinguish types, the types have to be actually different. You can't skip defining new types, therefore.

Related

How do you define a function type in Haskell?

I'm trying to store a function type in a definition so I can reuse it, but Haskell doesn't let me do it. A function type is not a data type , nor a class, as far as I understand them. So what am I doing wrong please?
functionType = Int -> Int -> Int -> Int -> Int -> Int -> Int
myfunction :: functionType -- <-- how do I declare this thing in a definition?
myfunction a b c d e f = a*b*c*d*e*f
Type aliases use the type keyword in their declaration; also, as usual for the declaration of new type forms, the newly declared alias must start with an upper case letter*. So:
type FunctionType = Int -> Int -- -> ...
functionValue :: FunctionType
functionValue a = a
* ...or punctuation. Why doesn't the usual "upper-case" punctuation restriction apply? No idea. I never thought about it before trying to write this answer, and now that I have, I find that a bit weird. Perhaps the upper-case restriction on the declaration of new types should be removed!

How can I find the definition of a Prelude function?

I'm currently trying to find the definition of the words function to help get an idea for a similar function I'm writing. So I was wondering is there somewhere that has all the definitions of the Prelude functions? Maybe a GHCi command to show the definition of one, or something on the Haskell wiki, I'm not sure.
Or if there isn't somewhere I can find that do any of y'all know what the definitions of words is?
Most packages on Hackage come with documentation that also includes a link to the source code for every function. You can usually find the function via Hoogle.
In the case of words, the Prelude documentation is found here, and the source is found at https://hackage.haskell.org/package/base-4.16.3.0/docs/src/Data.OldList.html#words:
-- | 'words' breaks a string up into a list of words, which were delimited
-- by white space.
--
-- >>> words "Lorem ipsum\ndolor"
-- ["Lorem","ipsum","dolor"]
words :: String -> [String]
{-# NOINLINE [1] words #-}
words s = case dropWhile {-partain:Char.-}isSpace s of
"" -> []
s' -> w : words s''
where (w, s'') =
break {-partain:Char.-}isSpace s'
This should in general also work with local documentation.
For ghci specifically, there are :info and :list commands, but :list words only produces an error message ("cannot list source code for words: module base-…:Data.OldList is not interpreted") for me.
Documentation of a function.
To search for the definition, look at hackage. In the case of words: https://hackage.haskell.org/package/base-4.16.3.0/docs/Prelude.html#v:words
Finding a function
To find a function, use hoogle. It is the de-facto tool for finding a function.
Example:
This is inside the shell. Hoogle can be installed at the samne time as when ghc is.
Find a function like so:
> hoogle "subtract"
Prelude subtract :: Num a => a -> a -> a
GHC.Num subtract :: Num a => a -> a -> a
Distribution.Compat.Prelude.Internal subtract :: Num a => a -> a -> a
GHC.Prelude subtract :: Num a => a -> a -> a
Hedgehog.Internal.Prelude subtract :: Num a => a -> a -> a
BasePrelude subtract :: Num a => a -> a -> a
RIO.Prelude subtract :: Num a => a -> a -> a
System.Metrics.Gauge subtract :: Gauge -> Int64 -> IO ()
ClassyPrelude subtract :: Num a => a -> a -> a
Algebra.Additive subtract :: C a => a -> a -> a
-- plus more results not shown, pass --count=20 to see more
The cool thing is, you can also search for types and functions with certain types. For example, here is the list of functions which will take an Int and return an Int.
hoogle "Int -> Int"
GHC.Unicode wgencat :: Int -> Int
System.Win32.DebugApi dr :: Int -> Int
Codec.Picture.Jpg.Internal.Common toBlockSize :: Int -> Int
Statistics.Function nextHighestPowerOfTwo :: Int -> Int
Numeric.SpecFunctions log2 :: Int -> Int
Math.NumberTheory.Logarithms intLog2 :: Int -> Int
Math.NumberTheory.Logarithms intLog2' :: Int -> Int
Streamly.Internal.Data.Array.Foreign.Mut.Type roundUpToPower2 :: Int -> Int
Streamly.Internal.System.IO arrayPayloadSize :: Int -> Int
Data.Array.Comfort.Shape triangleSize :: Int -> Int
-- plus more results not shown, pass --count=20 to see more

Number of arguments in Haskell code and type is different, why?

Can anybody explain the code below, what it does step by step, please. I know it is defining a function and its inputs, but what does (+) do, and why are there three Ints in plus and four Ints in plusplus's type, while it seems like there are only 3 arguments in plusplus's code?
plus :: Int -> Int -> Int
plus = (+)
plusPlus :: Int -> Int -> Int -> Int
plusPlus a b c = a + b + c
+ is the addition operator. Putting an operator in parentheses, like (+), refers to the addition function itself, as opposed to using + to add two numbers right on the spot. Basically, this:
plus = (+)
is equivalent to:
plus a b = a + b
Either way, it is defining plus to be a synonym for +.
In Haskell, -> is used to separate the types of the arguments, as well as the return value. So,
plus :: Int -> Int -> Int
is a function which takes two Ints and returns an Int.
plusPlus :: Int -> Int -> Int -> Int
is a function which takes three Ints and returns an Int.
The reason why the syntax is the same for the arguments and the return value is due to currying.
To be really pedantic,
plus :: Int -> Int -> Int -- ~ Int -> (Int -> Int)
is a function which takes an Int, and returns a function which takes an Int and returns an Int.
plusPlus :: Int -> Int -> Int -> Int -- ~ Int -> (Int -> (Int -> Int))
is a function which takes an Int, and returns a function which takes an Int, and returns a function which takes an Int and returns an Int.
In practice, it's convenient to speak of Haskell functions as taking multiple arguments. But technically, Haskell functions always take one argument. The argument type is on the left side of ->, and the return type is on the right side of ->, but the return type might itself be another function.

Haskell - Make a function with one case difference from an other function

I have a question about on how to change only one case of this structure:
type Foo a = String -> a
--Let's define a function.
foo :: Foo Int
foo "a" = 5
foo "b" = 6
foo "c" = 7
foo x = 0
Now suppose I want to create another function that gives me another function
but only changed in one case, this is what I did.
changeFoo :: Foo a -> String -> a -> Foo a
changeFoo = \foo -> \str -> \x -> (\str -> \x)
I'm new at programming Haskell and this doesn't seem to change only one case of the function. If someone can tell me what to do I'll be grateful.
Thanks in advance.
You need to check if the strings are equal or not. Something like
changeFoo :: (String -> Int) -> String -> Int -> String -> Int
changeFoo f s1 a s2
| s1 == s2 = a
| otherwise = f s2
I think changeFoo can be given a more general type though:
changeFoo :: Eq a => (a -> b) -> a -> b -> a -> b
Another way to write it even more generically is with the maybe type:
changeFoo :: (a -> b) -> (a -> Maybe b) -> a -> b
But that will clearly require a different implementation.
This solution is a bit overkill and only worth it if you already use the lens library in your project, but module Control.Lens.Prism offers a way to define "setters" for functions that override the behaviour of the functions for particular input values.
Suppose that we want we override the behaviour for "c" in your case. We begin by defining a Prism for "c" using only:
only "c"
-- This Prism compares for exact equality with a given value.
Then we build the "Setter for functions" using outside:
outside $ only "c"
The whole new definition:
foo' :: Foo Int
foo' = set (outside $ only "c") (\_ -> 77) foo
Testing it:
foo' "c"
>>> 77

How to declare function (type misunderstanding Maybe)

I need a function which works like:
some :: (Int, Maybe Int) -> Int
some a b
| b == Nothing = 0
| otherwise = a + b
Use cases:
some (2,Just 1)
some (3,Nothing)
map some [(2, Just 1), (3,Nothing)]
But my code raise the error:
The equation(s) for `some' have two arguments,
but its type `(Int, Maybe Int) -> Int' has only one
I don't understand it.
Thanks in advance.
When you write
foo x y = ...
That is notation for a curried function, with a type like:
foo :: a -> b -> c
You have declared your function to expect a tuple, so you must write it:
some :: (Int, Maybe Int) -> Int
some (x, y) = ...
But Haskell convention is usually to take arguments in the former curried form. Seeing funcitons take tuples as arguments is very rare.
For the other part of your question, you probably want to express it with pattern matching. You could say:
foo :: Maybe Int -> Int
foo Nothing = 0
foo (Just x) = x + 1
Generalizing that to the OP's question is left as an exercise for the reader.
Your error doesn't come from a misunderstanding of Maybe: The type signature of some indicates that it takes a pair (Int, Maybe Int), while in your definition you provide it two arguments. The definition should thus begin with some (a,b) to match the type signature.
One way to fix the problem (which is also a bit more idiomatic and uses pattern matching) is:
some :: (Int, Maybe Int) -> Int
some (a, Nothing) = a
some (a, Just b) = a + b
It's also worth noting that unless you have a really good reason for using a tuple as input, you should probably not do so. If your signature were instead some :: Int -> Maybe Int -> Int, you'd have a function of two arguments, which can be curried. Then you'd write something like
some :: Int -> Maybe Int -> Int
some a Nothing = a
some a (Just b) = a + b
Also, you might want to add the following immediate generalization: All Num types are additive, so you might aswell do
some :: (Num n) => n -> Maybe n -> n
some a Nothing = a
some a (Just b) = a + b
(I've violated the common practice of using a, b, c... for type variables so as not to confuse the OP since he binds a and b to the arguments of some).

Resources