Tried to use (.) for function composition, but it doesn't work.
import Data.String (length, trim)
trimmedLength :: String -> Int
trimmedLength = length . trim
Function composition in PureScript is done with (<<<), not (.).
import Data.String (length, trim)
trimmedLength :: String -> Int
trimmedLength = length <<< trim
Related
I am solving a problem in which I have to count all the even numbers in an array in purescript. I have written down code but I am facing type mismatch error.
import Data.Array (null)
import Data.Array.Partial (tail,head)
import Partial.Unsafe (unsafePartial)
import Math
iseven :: Int -> Boolean
iseven a = mod a 2 == 0
len :: forall a. Array a -> Int
len arr =
if null arr
then 0
else
if iseven unsafePartial head arr
then 1 + len (unsafePartial tail arr)
else len (unsafePartial tail arr)
But I am getting an error.
Error found:
in module $PSCI
at :6:18 - 6:40 (line 6, column 18 - line 6, column 40)
Could not match type
a1
with type
Int
while checking that type t0
is at least as general as type Int
while checking that expression (unsafePartial head) arr
has type Int
in binding group len
where a1 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
t0 is an unknown type
I am new to purescript so I am not able to understand the error.
When you write unsafePartial head arr, that means "apply function unsafePartial to two arguments, first argument head and second argument arr, but this is not what you want to do.
What you want to do is first calculate head arr, and only then apply unsafePartial to the result of that.
To achieve this, use parentheses:
unsafePartial (head arr)
Or the $ operator:
unsafePartial $ head arr
After you have fixed that, the next error you're getting is about what iseven expects as argument and what you're passing to it. The signature of len says forall a. Array a ->, which means "I will work with arrays of any type", but in reality it's trying to pass an element of that array to iseven, which expects an Int. So your function promised to work with anything, but actually wants Int.
To fix, make the signature tell the truth: the function wants an array of Ints:
len :: Array Int -> Int
I am new to ML, here is my attemp to writing a function that receives:
list of strings L
string str
int counter
the function should return the number of occurrences of str in L
Here is my code:
(*
* return number of occurences of str in L
* count should be initialized to zero.
*)
fun aux_num_of_occur(L: string list) (str:string) (count:int) =
if null L then 0
else if str = hd(L) then
aux_num_of_occur tl(L) str (count+1)
else
aux_num_of_occur tl(L) str count
Those are the errors i got:
Error: case object and rules don't agree [tycon mismatch]
rule domain: string list * string * int
object: ('Z list -> 'Z list) * 'Y * 'X
in expression:
(case (arg,arg,arg)
of (L : string list,str : string,count : int) =>
if null L
then 0
else if <exp> = <exp> then <exp> <exp> else <exp> <exp>)
uncaught exception Error
raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
../compiler/TopLevel/interact/evalloop.sml:44.55
../compiler/TopLevel/interact/evalloop.sml:296.17-296.20
My Questions:
What is wrong with the syntax?
it is not clear to me what the error message says: what is a
rule and an object in this case?
how can i return a int by recursively calling a function? is it by passing to it a counter as an argument?
This is a classical mistake: tl(L) and tl L are the same thing -- you don't need parentheses for function application in ML-like languages, you just juxtapose the function and the argument(s).
So aux_num_of_occur tl(L) ... is the same thing as aux_num_of_occur tl L ..., i.e. you are trying to apply aux_num_of_occur to the tl function, not to a list of strings. Now, the tl function has type 'a list -> 'a list and that is what you see in the error message (with 'a being 'Z there).
I ought to say that this style with those null, hd, and tl functions is not very idiomatic in SML -- you could use pattern-mathing instead. It is also more convenient to make aux_num_of_occur local to prevent namespace pollution, prevent incorrect usage (you control the initial value of count). Additionally, this gives you the advantage of not passing str all the time when recursing further.
fun num_of_occur ss str =
let
fun loop [] count = count
| loop (s::ss) count =
if s = str
then loop ss (count + 1)
else loop ss count
in
loop ss 0
end
Notice that num_of_occur has a more general type ''a list -> ''a -> int, where ''a means any type with equality comparison. The compiler will generate a warning
Warning: calling polyEqual
which you can either ignore or add some type annotations to num_of_occur. See here for more detail.
In F# I am trying to write a function that given two strings it will return all indexes of the start of the second string in the first string. My function looks like this:
let allIndexOf (str:string) (c:string) =
let rec inner (s:string) l =
match (s.IndexOf(c), (s.IndexOf(c)+1) = s.Length) with
| (-1, _) -> l
| (x, true) -> x::l
| (x, false) -> inner(s.Substring(x+1) x::l)
inner str []
The problem is on the line (x, false) -> inner(s.Substring(x+1) x::l) the compiler says expected type int list but got int list -> int list. What am I doing wrong here?
In this case I want to call inner with the rest of the string (minus the part where it matched) to look for more matches.
Did you forget the parens between the first and the second argument?
| (x, false) -> inner (s.Substring(x+1)) (x::l)
Can I write a function which returns the name of the function given as the argument?
let funName f: string =
// returns the name of f.
For example, if I pass printfn as an argument to funName, it returns "printfn".
> funName printfn;;
val it : string = "printfn"
EDIT: I wanted to write a function doc which returns the XML documentation associated with the given function.
let doc f = // returns the XML documentation of the function `f`.
To retrieve the summary of the function using something like NuDoq, I wanted to know the name of the function.
I cannnot imagine why you would want to do this and I do not think that there's a way to do this with reflection, but F# Code Quotations might get you halfway there.
open Microsoft.FSharp.Quotations
let rec funName = function
| Patterns.Call(None, methodInfo, _) -> methodInfo.Name
| Patterns.Lambda(_, expr) -> funName expr
| _ -> failwith "Unexpected input"
let foo () = 42
funName <# foo #> // "foo"
But note that certain predefined library functions have a divergent internal name.
funName <# printfn #> // "PrintFormatLine"
funName <# id #> // "Identity"
Note that as of F# 4.0, class types can automatically quote their arguments, simplifying the call site compared to kaefer's answer:
open Microsoft.FSharp.Quotations
type DocumentGetter =
static member GetName([<ReflectedDefinition>]x:Expr<_->_>) =
match x with
| DerivedPatterns.Lambdas(_, Patterns.Call(_,methodInfo,_)) ->
methodInfo.Name
let f x y = x + y
DocumentGetter.GetName f
I was doing the exercises in here http://book.realworldhaskell.org/read/functional-programming.html . My solution to the problem where I need to transpose a text file seems to take a lot of CPU time. How can I improve below algorithm, if I could, to make it less CPU hungry.
import System.Environment (getArgs)
import Data.Char(isAlpha)
interactWith function inputFile outputFile = do
input <- readFile inputFile
writeFile outputFile (function input)
main = mainWith myFunction
where mainWith function = do
args <- getArgs
case args of
[input,output] -> interactWith function input output
_ -> putStrLn "error: exactly two arguments needed"
-- replace "id" with the name of our function below
myFunction = transpose
transpose :: String -> String
transpose input = tpose (lines input)
tpose [] = []
tpose xs = concat (map (take 1) xs) ++ "\n" ++ tpose (map (drop 1) xs)
Skip up to chapter 8, which talks about how inefficient the String datatype is, and proposes using ByteString instead. There's also Data.Text, if your file is unicode.
The Data.List module contains some useful functions, such as transpose :: [[a]] -> [[a]]. There's also lines and unlines in the Prelude, which convert between a String and a [String] (by breaking on newlines).
So basically, you probably want something like
main = do
[input,output] <- getArgs
interactWith (unlines . transpose . lines) input output