Currying and compiler design - currying

This is a homework question:
Explain the transformations the type
of a routine undergoes in partial
parameterization.
So far I understand currying. But I cannot find any resources on how a function like this is implemented by the compiler in memory. Could I be pointed in the right direction, maybe keywords to search for or links to resources or possibly an explanation here of how the compiler generates the type and symbol table among other things thats related to the question.
Thanks.

Currying is the conversion of n argument functions into n unary functions:
Example, if you have a ternary function f :: t1 x t2 x t3 -> t you can represent this function as
f1 :: t1 -> (t2 -> (t3 -> t))
In other words, f1 is a function which takes an argument of type t1 and returns a function of type f2.
f2 :: t2 -> (t3 -> t)
f2 is a function which takes an argument of type t2 and returns a function of type f3.
f3 :: t3 -> t
f3 is a function which takes an argument of type t3 and returns type t.
Example, if f(a,b,c) = a+b*c then:
f3(C) == c1+c2*C where c1 and c2 are constant.
f2(B) == f3(C) where c1 is constant and c2 is replaced with B.
f1(A) == f2(B) where c1 is replaced with A.
In functional languages, functions are first class citizens so its common to have them as return type.

Currying is like fixing a parameter of the function. What you really need to modify is the prototype of the function called.. if you have for example retn_type function(param1, param2) and you currying it on first parameter you set it to a fixed value and you obtain a new function retn_type(param2) that can be called and passed in a different way from the original one.
Actually you can obtain it in a compiler in many ways or hacks but the core of everything to its simplicity is just to redefine a new version that is linked to first one. So when you call retn_type(param2) you execute the same code of first function assuming that parameter1 is specified by curryfication.

Related

Converting MATNR via conversion exit fails for custom table

I'm trying to select the latest date of a material movement from MSEG, but the material needs to be in stock and that is sourced from a bespoke table which uses unconverted Material names.
I've tried using the CALL FUNCTION 'CONVERSION_EXIT_MATN1_OUTPUT' (and INPUT) but I'm not sure how to properly utilize it in a select statement.
IF MSEG-BWART = '101'.
CALL FUNCTION 'CONVERSION_EXIT_MATN1_OUTPUT'
EXPORTING
INPUT = ZBJSTOCK-ZMAT10
IMPORTING
OUTPUT = WA2-MATNR.
SELECT MAX( BUDAT_MKPF )
FROM MSEG
INTO GRDT
WHERE MATNR = WA2-MATNR.
ENDIF.
Currently, WA2-MATNR seems to come out as blank and therefore is not pulling the data from MSEG.
You shouldn't use conversion exit here. Material number in SAP tables lays in internal (INPUT) format and you are converting it into readable format (OUTPUT) in order to query table. It is obvious you will not find anything.
Sample:
MATNR internal format (for OUT exits)
000000000000025567
MATNR external format (for IN exits)
25567
Conversions cases:
000000000000025567 -> CONVERSION_EXIT_MATN1_OUTPUT -> 25567 ✔️
25567 -> CONVERSION_EXIT_MATN1_OUTPUT -> 25567 ❌ nothing changes
25567 -> CONVERSION_EXIT_MATN1_INPUT -> 000000000000025567 ✔️
000000000000025567 -> CONVERSION_EXIT_MATN1_INPUT -> 000000000000025567 ❌ nng changes
Most likely, your bespoke table contains faulty material number so exit doesn't return anything. Or material number in format that exit doesn't expect, e.g. 19 characters instead of 18 and so on.
P.S.
Just for you info, you can use templates for conversion. It is the same as calling conversion FMs
SELECT SINGLE matnr FROM mara INTO #DATA(l_matnr) WHERE EXISTS ( SELECT * FROM mseg WHERE matnr = mara~matnr ).
l_matnr = | { l_matnr ALPHA = OUT } |. <<-- templating
SELECT SINGLE matnr, budat_mkpf
FROM mseg
INTO #DATA(l_mkpf)
WHERE matnr = #l_matnr.
In the above sample SELECT will not return anything, but if you comment out the template line it will.
Unless you’ve added code into the user exits in that function, it’s not going to do what you want. The standard purpose of that function is to format the material number for display on the screen.
The quickest way to do what you want is to select from your custom table to do the lookup.
That said, there is a user exit in that function where you can code the select to do the lookup. The extra benefit of doing that is that your users will be able to type in the legacy material number and the system will switch it with the new one.

Force FsCheck to generate NonEmptyString for discriminating union fields of type string

I'm trying to achieve the following behaviour with FsCheck: I'd like to create a generator that will generate a instance of MyUnion type, with every string field being non-null/empty.
type MyNestedUnion =
| X of string
| Y of int * string
type MyUnion =
| A of int * int * string * string
| B of MyNestedUnion
My 'real' type is much larger/deeper than the MyUnion, and FsCheck is able to generate a instance without any problem, but the string fields of the union cases are sometimes empty. (For example it might generate B (Y (123, "")))
Perhaps there's some obvious way of combining FsCheck's NonEmptyString and its support for generating arbitrary union types that I'm missing?
Any tips/pointers in the right direction greatly appreciated.
Thanks!
This goes against the grain of property based testing (in that you explicitly prevent valid test cases from being generated), but you could wire up the non-empty string generator to be used for all strings:
type Alt =
static member NonEmptyString () : Arbitrary<string> =
Arb.Default.NonEmptyString()
|> Arb.convert
(fun (nes : NonEmptyString) -> nes.Get)
NonEmptyString.NonEmptyString
Arb.register<Alt>()
let g = Arb.generate<MyUnion>
Gen.sample 1 10 g
Note that you'd need to re-register the default generator after the test since the mappings are global.
A more by-the-book solution would be to use the default derived generator and then filter values that contain invalid strings (i.e. use ==>), but you might find it not feasible for particularly deep nested types.

Coq - Passing parameters to a record

I'm having trouble in comparing elements of sets belonging to two distinct
instances of the same record type. Consider the following record.
Record ToyRec := {
X:Set;
Labels:Set;
r:X->Labels
}
Say that two objects T1 and T2 of type ToyRec form a good pair if
for every element in T1.(X) there exists an element in T2.(X) with the
same label.
Definition GoodPair(T1 T2:ToyRec):Prop :=
forall x1:T1.(X), exists x2:T2.(X), T1.(r) x1 = T2.(r) x2.
The problem is that I get an error saying that T1.(r) x1 is of type X1.(Labels),
and T2.(r) x2 is of type X2.(Labels).
I understand the problem, and I imagine it could be solved if I could somehow
declare the set Labels outside the record, and then pass it as a parameter.
Is there a way to do this in Coq? Or what would be the most elegant way of
defining the records I want and the property GoodPair?
The closest thing I got from your code his the following:
Record ToyRec {Labels : Set} := {
X:Set;
r:X->Labels
}.
Definition GoodPair {Labels:Set} (T1 T2 : #ToyRec Labels) : Prop :=
forall x1: X T1, exists x2: X T2, r T1 x1 = r T2 x2.
By having Labels as a dependency for ToyRec you can be sure that both records are using the same type.
PS: I used {Labels : Set} instead of (Labels : Set) to specify that this argument is implicit and should be inferred whenever possible.

Partial SQL insert in haskelldb

I just started a new project and wanted to use HaskellDB in the beginning. I created a database with 2 columns:
create table sensor (
service text,
name text
);
..found out how to do the basic HaskellDB machinery (ohhh..the documentation) and wanted to do an insert. However, I wanted to do a partial insert (there are supposed to be more columns), something like:
insert into sensor (service) values ('myservice');
Translated into HaskellDB:
transaction db $ insert db SE.sensor (SE.service <<- (Just $ senService sensor))
But...that simply doesn't work. What also does not work is if I specify the column names in different order, which is not exactly conenient as well. Is there a way to do a partial insert in haskelldb?
The error codes I get are - when I just inserted a different column (the 'name') as the first one:
Couldn't match expected type `SEI.Service'
against inferred type `SEI.Name'
Expected type: SEI.Intsensor
Inferred type: Database.HaskellDB.HDBRec.RecCons
SEI.Name (Expr String) er
When using functional dependencies to combine
Database.HaskellDB.Query.InsertRec
(Database.HaskellDB.HDBRec.RecCons f (e a) r)
(Database.HaskellDB.HDBRec.RecCons f (Expr a) er),
etc..
And when I do the 'service' as the first - and only - field, I get:
Couldn't match expected type `Database.HaskellDB.HDBRec.RecCons
SEI.Name
(Expr String)
(Database.HaskellDB.HDBRec.RecCons
SEI.Time
(Expr Int)
(Database.HaskellDB.HDBRec.RecCons
SEI.Intval (Expr Int) Database.HaskellDB.HDBRec.RecNil))'
against inferred type `Database.HaskellDB.HDBRec.RecNil'
(I have a couple of other columns in the table)
This looks really like 'by design', unfortunately :(
You're right, that does look intentional. The HaskellDB.Query docs show that insert has a type of:
insert :: (ToPrimExprs r, ShowRecRow r, InsertRec r er) => Database -> Table er -> Record r -> IO ()
In particular, the relation InsertRec r er must hold. That's defined elsewhere by the recursive type program:
InsertRec RecNil RecNil
(InsertExpr e, InsertRec r er) => InsertRec (RecCons f (e a) r) (RecCons f (Expr a) er)
The first line is the base case. The second line is an inductive case. It really does want to walk every element of er, the table. There's no short-circuit, and no support for re-ordering. But in my own tests, I have seen this work, using _default:
insQ db = insert db test_tbl1 (c1 <<- (Just 5) # c2 << _default)
So if you want a partial insert, you can always say:
insC1 db x = insert db test_tbl1 (c1 <<- (Just x) # c2 << _default)
insC2 db x = insert db test_tbl2 (c1 << _default # c2 <<- (Just x))
I realize this isn't everything you're looking for. It looks like InsertRec can be re-written in the style of HList, to permit more generalization. That would be an excellent contribution.

Linq, VB - Anonymous type cannot be converted to anonymous type

I'm a Linq noobie, maybe someone can point me in the right direction. What's wrong here? These anonymous types seem to have the same signatures.
'*** Get all of the new list items'
Dim dsNewFiles = From l1 In list1 _
Where Not (From l2 In list2 _
Select l2.id, l2.timestamp).Contains(New With {l1.id, l1.timestamp})
I wish there were some way to highlight in the above code, but I get the compile error:
Value of type '<anonymous type> (line n)' cannot be converted to '<anonymous type> (line n)'.
on the ".Contains(New With{l1.id, l1.timestamp})"
I assume it thinks the anonymous types are different in some way, but the id and timestamp columns are the same in either list. They are also in the same order. What else can be different between the two?
[Edit 7/10/2009 16:28 EST]
I tried the suggested code from user Meta-Knight (New With {Key l1.id, l1.timestamp}) and it fixed the compile error. However, when I ran the code with List1 and List2 as follows:
List1 List2
id timestamp id timestamp
-- ---------- -- ----------
01 2009-07-10 00:00:00 01 2009-07-10 00:00:00
The result was:
dsNewFiles
id timestamp
-- ----------
01 2009-07-10 00:00:00
It should have been an empty list.
Just change the last part of your code to:
New With {Key l1.id, Key l1.timestamp}
I tested the code and it works.
Edit:
I don't know why this doesn't work for you, I'll post the whole code just to be sure.
Dim dsNewFiles = From l1 In list1 _
Where Not (From l2 In list2 _
Select l2.ID, l2.TimeStamp).Contains(New With {Key l1.ID, Key l1.TimeStamp})
Another option is to simply do the following:
Dim dsNewFiles = list1.Except(list2)
For this to work, your class must override Equals and GetHashCode, and implement the IEquatable(Of T) interface. There's a very good example on MSDN (at the bottom).
If ID and Timespan don't represent equality in your class, you can use a custom IEqualityComparer(Of T) as a second argument.
When you generate anonymous types, they will be generated as separate types if they don't specify their properties with the same name and in the same exact order. So your example is the same as if I did this:
Class A
BeginClass
Begin ID as Int Begin ... End
Stuff as String Begin ... End
EndClass
Class B
BeginClass
Begin Stuff as String Begin ... End
ID as Int Begin ... End
EndClass
From a In someListofAs
Where Not (From b In someListofBs Select b).Contains(a)
That's complete air code, btw.
Also, in your example one part of your LINQ is an anonymous type and the other isn't. That might be your problem.
Try this:
From l1 In list1 _
Where Not (From l2 In list2 _
Select New With { ID = l2.id, Timestamp = l2.timestamp}).Contains(
New With { ID = l1.id, Timestamp = l1.timestamp})