how to use map append correctly with lists of list in Racket - racket

i have this code :
(: min&max-lists : (Listof (Listof Any)) -> (Listof Any))
(define (min&max-lists lst)
(apply append
(map (lambda (slst)
(sublist-numbers slst) ;; **
(cons (sublist-numbers slst) '()) ;; *
)
lst)))
if I run this code with the line with two ** everything works fine, but when I run the code above with the line with one * it shows me like that :
Type Checker: type mismatch
expected: (Listof Any)
given: Any in: slst
how can I solve this? I see if i use the slst with another function it shows me that it is typed if Any and they need List of Any but if I use it like with two ** it works fine

The problem with (cons (sublist-numbers slst) '()):
(cons x '()) ;; => '(x)
;; which is nothing other than:
(list x)
If x is already a list - like in this case)
you have instead of '(1 2 3) one list layer around it: '((1 2 3)).
If you apply-append such results you get (Listof (Listof Any)) instead of just (Listof Any).
So, if you want to run using the line *, you have to change the typing to:
(: min&max-lists : (Listof (Listof Any)) -> (Listof (Listof Any)))

Related

Applying to potentially empty lists in Typed Racket

The following is no problem in untyped racket:
(apply hc-append
(for/list ([colour '("red" "green" "blue")])
(colorize (filled-rectangle 10 10) colour)))
The result is a pict with three differetnly coloured squares.
But it's not possible in Typed Racket. First, for/list needs a type annotation:
(apply hc-append
(for/list : (Listof pict)
([colour '("red" "green" "blue")])
(colorize (filled-rectangle 10 10) colour)))
But then, the types of (curry apply hc-append) and the result of the (for/list …) form don't align:
; […] Type Checker: Bad arguments to function in `apply':
; Domains: pict pict *
; Real pict pict *
; Arguments: (Listof pict)
This error message looks puzzling, but it comes down to the fact that (Listof pict) may be empty, and hc-append's type signature requires pict pict *, i.e. at least one pict.
But this works in both typed and untyped Racket:
(apply hc-append (map (curry colorize (filled-rectangle 10 10))
'("red" "green" "blue")))
The type of the (map …) form is (Pairof pict (Listof pict)). Great! That's a non-empty list. But I can't use that in the for/list form as a type annotation, the type checker rejects it.
Even if I carefully pick apart the types:
(let ([potentially-empty-list
(for/list : (Listof pict)
([c '("red" "green" "blue")])
(colorize (filled-rectangle 10 10) c))])
(cond
[(null? potentially-empty-list) (blank)]
[else (apply hc-append #{(list (first potentially-empty-list)
(rest potentially-empty-list))
: (Pairof pict (Listof pict))})]))
I end up with a very confusing message, essentially the same, but now it defies my original justification! Namely, that the list may be empty. The type clearly states that it may not be empty! Racket rejects it:
; […] Type Checker: Bad arguments to function in `apply':
; Domains: pict pict *
; Real pict pict *
; Arguments: (List pict (Listof pict))
Two things confuse me:
Instead of my original (Pairof pict (Listof pict)), Racket turns the type into (List pict (Listof pict)). I think that's OK, because the two should be equivalent.
But if they're equivalent then I would expect the (apply …) form to work, as in the (map …) case! There, too, we use (apply hc-append ls) where ls has type (Pairof pict (Listof pict)).
My intuiton is that at least the last example should work, but it does not, and I don't understand why.
Your following code is pretty close.
(let ([potentially-empty-list
(for/list : (Listof pict)
([c '("red" "green" "blue")])
(colorize (filled-rectangle 10 10) c))])
(cond
[(null? potentially-empty-list) (blank)]
[else (apply hc-append #{(list (first potentially-empty-list)
(rest potentially-empty-list))
: (Pairof pict (Listof pict))})]))
However, there are two mistakes.
(list (first ....) (rest ...)) is a list of two elements, where the first element is a pict and the second element is a (Listof pict). I.e. it has type (List pict (Listof pict)). I think you instead want to use (cons (first ....) (rest ...)), which has type (Pairof pict (Listof pict) = (Listof pict) that guarantees it has at least one element.
You should use #{(cons ...) :: (Pairof ...)} instead. The #{x : t} notation is only valid in binding positions, particularly when x is a variable. The #{e :: t} notation however allows e to be an arbitrary expression, which is what you are doing here. Typed Racket does appear to be buggy in a sense that it doesn't report a misuse of #{x : t} when x is not a variable. I'll file a bug report.
Following program works:
#lang typed/racket
(require typed/pict)
(let ([potentially-empty-list
(for/list : (Listof pict)
([c '("red" "green" "blue")])
(colorize (filled-rectangle 10 10) c))])
(cond
[(null? potentially-empty-list) (blank)]
[else (apply hc-append #{(cons (first potentially-empty-list)
(rest potentially-empty-list))
:: (Pairof pict (Listof pict))})]))
Here's a simplification I came up with thanks to Sorawee's answer:
(: safe-apply (∀ (E R) (→ R (→ E E * R) (Listof E) R)))
(define (safe-apply def f ls)
(cond
[(null? ls) def]
[else (apply f ls)]))
The fun part is that Occurrence Typing in Racket will make ls have type (Pairof E (Listof E)) in the else clause of cond.
This can then be used like so:
(safe-apply (blank)
hc-append
(for/list : (Listof pict)
([colour '("red" "green" "blue")])
(colorize (filled-rectangle 10 10) colour)))

Going over a list of strings to find the string with the needed prefix

I need to define the function plPrefixContained – that consumes 5 strings and
returns the first one that contains the string "pl" as a prefix – if one such
exists, and returns #f otherwise.
What I'm trying to do is to use the prefixes function to go over all the strings in the list and check their prefixes, put them in a new list and to output the first string as the result.
(I will handle the #f case later) my code is down below but it keeps giving me the error-
first: contract violation
expected: (and/c list? (not/c empty?))
given: '()
any help would be appreciated
(: plPrefixContained : String String String String String -> String)
(define (plPrefixContained x y z w v)
(list-ref (prefixes (list x y z w v) '()) 0))
(: prefixes : (Listof String) (Listof String) -> (Listof String))
(define (prefixes lis em)
(cond
[(and (eq? (string-ref (first lis) 0) "p") (eq? (string-ref (first lis) 1) "l"))
(cons (first lis) em)]
[else
(prefixes (rest lis) em)]))
this is how I want my output to be like-for example
(test (plPrefixContained "yypl" "opl" "lpTT" "plpl" "lol")
=>
"plpl")
There are two problems:
intensional equality eq?, instead of extensional equality such as equal? or string=?
comparing string / char, instead of comparing char / char or string / string
You are using eq?, which always makes me suspicious. eq? uses "intensional" equality, which is basically pointer equality, meaning that a string which is allocated somewhere in memory won't necessarily be eq? even if it has the same characters. You can see this with (eq? "abc123" (string-append "abc" "123")).
If you're dealing with strings, lists, or any other data which "contains" things, you should avoid eq?. Instead you should use an "extensional" equality predicate such as equal?, or even better, a predicate specific to the types of values you expect, such as string=?. Here's how they behave better than eq?:
> (eq? "abc123" (string-append "abc" "123"))
#f
> (equal? "abc123" (string-append "abc" "123"))
#t
> (string=? "abc123" (string-append "abc" "123"))
#t
Since you're comparing using the strings "p" and "l", I should be able to substitute eq? with string=? in your code:
(: prefixes : (Listof String) (Listof String) -> (Listof String))
(define (prefixes lis em)
(cond
[(and (string=? (string-ref (first lis) 0) "p") (string=? (string-ref (first lis) 1) "l"))
(cons (first lis) em)]
[else
(prefixes (rest lis) em)]))
However, this reveals the second problem, which I only spotted after seeing the error message:
string=?: contract violation
expected: string?
given: #\y
argument position: 1st
other arguments...:
"p"
The string=? isn't working because its first argument, the result of string-ref, is a character (like #\y), not a string. To fix this, use char=? instead of string=?, and compare with the characters #\p and #\l instead of the strings "p" and "l".
(: prefixes : (Listof String) (Listof String) -> (Listof String))
(define (prefixes lis em)
(cond
[(and (char=? (string-ref (first lis) 0) #\p) (char=? (string-ref (first lis) 1) #\l))
(cons (first lis) em)]
[else
(prefixes (rest lis) em)]))

Can I divide list into multiple parts in BSL?

I have the list of values and want to take first x values from it and create (list (listof first x values) (listof next x values) and so on until this list gets empty...).
For example, given this list: (list "a" "b" "c" "d" "e" "f" "g" "h" "t")
return this: (list (list a" "b" "c") (list "d" "e" "f") (list "g" "h" "t"))
Thanks in advance :)
Remember what a datatype for a list is. Your class is probably doing something like:
;; A IntegerList is one of:
;; - '()
;; - (cons Integer IntegerList)
Given that, your template should reflect this structure. I will solve the base case (where we want to turn a list of integers into lists of one integers.
First I will define a 1List datatype as:
;; a 1List is:
;; - (cons Integer '())
Next, the purpose statement and signature for the function will be:
;; Takes a list of integers and returns a list of 1Lists of the same integers
;; IntegerList -> 1List
(define (make-1list lst)
...)
Okay cool. Now we need test cases:
(check-expect (make-1list (list 1 2 3)) (list (list 1) (list 2) (list 3)))
(check-expect (make-1list (list)) (list))
(check-expect (make-1list (list 42)) (list (list 42)))
Finally, I can make my template:
(define (make-1list lst)
(cond [(null? lst) ...]
[else ... (first lst) ... (rest lst) ...]))
(Note that it sometimes makes sense to make some of the template first, to help you guide what tests you need.)
Finally, we can fill in our code:
(define (make-1list lst)
(cond [(null? lst) '()]
[else (cons (list (first lst)) (make-1list (rest lst)))]))
And finally, are examples are also tests so we just need to run them to make sure everything works.
Now, since you want to make 3Lists instead of 1Lists, do you see how you can follow this recipe to solve the problem?
Write down your data definition.
Make your purpose statement and signature.
Make your examples.
Make your template.
Write the actual function.
Turn your existing examples into tests.
Following this pattern should help you break the problem down into smaller steps. Good luck.
Better way to accomplish this task is to use accumulators & recursion.

Could not undersand racket function

My proffesor gave us this function:
(: every? : (All (A) (A -> Boolean) (Listof A) -> Boolean))
(define (every? pred lst)
(or (null? lst)
(and (pred (first lst))
(every? pred (rest lst)))))
I couldn't understand the meaning of: All (A) (A -> Boolean).
please can someone can explain to me - what is the meaning of the variable, what the function get, what is it do and what is it return because i can't figure it out.
Let's give the function every? a spin at the repl:
> (every? even? (list 1 2 3 4))
#f
> (every? char? (list #\a #\b #\c))
#t
Note that the type of the first list (list 1 2 3 4) is (Listof Number).
The type of the second list (list #\a #\b #\c) is (Listof Char).
What type should the lst argument of every? have?
Clearly it needs to be a list, but what type are the elements?
We don't know, so we make it a (Listof A), where A stands
for some (unknown) type.
However the predicate pred is called on the elements in the list,
so the type must match. In the first example: even? has the type
"function from number to boolean" aka (A -> Boolean).
In general we need the type: (A -> Boolean) for the predicate.
This becomes:
(: every? : (All (A) (A -> Boolean) (Listof A) -> Boolean))

Defining a function that accepts a List of Lists in racket

My assignment is to count how many lists I have with length 3 in my list (List of List).
I thought I built everything correctly, but when I want to send the first list to my recursive function it fails because my list has the type Any, and I can't find a way to make it a list of lists.
#lang pl
(: count-3lists : (Listof Any) -> Number)
(define (count-3lists l)
(cond
[(null? l) 0]
[else (+ (count-3lists-helper (first l)) (count-3lists (rest l)))]))
(: count-3lists-helper : (Listof Any) -> Number)
(define (count-3lists-helper l)
(cond [(= (length l) 3) 1]
[else 0]))
(: length : (Listof Any) -> Number)
(define (length l)
(cond
[(null? l) 0]
[else (add1 (length (rest l)))]))
The error I get is:
. Type Checker: Polymorphic function `first' could not be applied to
arguments:
Types: (Pairof a (Listof b)) -> (a : ((! False # (car) (0 0)) | (False # (car) (0 0))) : (car (0 0)))
(Listof a) -> a
Arguments: (Pairof Any (Listof Any))
Expected result: (Listof Any)
in: (first l)
It seems like you want your count-3lists function to take a list of lists as its input. Right now you have (Listof Any).
What you want is express something like (Listof List), but the inner list has to be a list of something, so you can write that as (Listof (Listof Any)).
Then the first part of your code becomes this:
(: count-3lists : (Listof (Listof Any)) -> Number)
(define (count-3lists l)
(cond
[(null? l) 0]
[else (+ (count-3lists-helper (first l)) (count-3lists (rest l)))]))
After that, the rest of your code works. It turns out that your length function was fine. (So you should probably rename your question.)