Data.Map,函数作为Haskell中的值

时间:2016-08-07 19:50:49

标签: haskell dictionary maybe

我是一名Haskell新手试图了解如何使用{$data.101} 结构,惰性评估和Data.Map类型。

在Python中,我可以定义一个值为函数的字典结构。给定一个键我就可以使用相应的函数:

Maybe

我试图在Haskell中做类似的事情,但它没有编译。

d = {"+": lambda x,y: x+y}

def f(key, v1, v2):
    if key in d:
        return d[key](v1, v2)
    else:
        return 0

这不会编译并返回错误,如

d = Map.fromList [('+', (+))]

f :: Char -> Integer -> Integer -> Integer
f key v1 v2 =
    if k == Nothing
        then 0
        else f v1 v2
    where
        k = Map.lookup key d
        (Just f) = k

我相信这是因为No instance for (Eq (Integer -> Integer -> Integer)) 只返回Map.lookup '+' d而不是Maybe (Integer -> Integer -> Integer)(Just (+))的实例。我认为这与懒惰的评估有关。

是否有像Haskell一样的方式来做这种事情?我是否正确使用了Maybe类型?我可以强制评估查找吗?

这是因为我试图在Haskell中实现反向抛光计算器。我用字典来组织我可以使用的功能。我找到了一个没有字典的好解决方案(https://rosettacode.org/wiki/Parsing/RPN_calculator_algorithm#Haskell),但现在我只想了解如何正确访问Haskell Nothing中的值。

3 个答案:

答案 0 :(得分:9)

问题在于这个表达式:k == Nothing

它需要k来支持相等性测试。 k的类型为Maybe (Integer -> Integer -> Integer)。如果Maybe TT,则Integer -> Integer -> Integer支持等式测试,但Maybe (Integer -> Integer -> Integer)不支持:您无法比较函数是否相等。所以整个表达都没有进行类型检查。

我不知道“ Maybe (Integer -> Integer -> Integer) ”的实例是什么意思:类有实例(类型),但Eq不是类,这是一种普通的类型。相关课程为==(提供Eq方法)。问题是函数类型没有f key v1 v2 = case Map.lookup key d of Nothing -> 0 Just f -> f v1 v2 -- but consider naming 'f' something else; -- the surrounding function is already called 'f' 实例。这与懒惰评估无关。

解决方案是仅使用模式匹配:

Maybe

或者,您可以使用f key v1 v2 = maybe 0 (\f -> f v1 v2) (Map.lookup key d) 辅助函数之一:

f key v1 v2 =
    fromMaybe (\_ _ -> 0) (Map.lookup key d) v1 v2

甚至:

    <link type="text/css" href="css/writers.css" rel="stylesheet" />
    <style>
        body {padding: 0 20px;}
        .limited-offer {
            background-color: white;
            padding:  3px;
            margin-bottom: 12px;
            border-radius: 4px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="row">
            <img id="img-writers" src="#" alt="images" />
            <div class="col-md-12">
                <form id="form-writers" method="post" class="form-horizontal well pull-left">
                    <h1>Writers</h1>
                    <div class="form-group">
                        <label for="title" class="col-lg-3 control-label">Title</label>
                        <div class="col-lg-9">
                            <input type="text" class="form-control" required id="title" name="title" autofocus="true" placeholder="Title" />
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="form-type" class="col-lg-3 control-label">Type of work</label>
                        <div class="col-lg-9">
                            <select class="form-control" required id="form-type" name="form-type"></select>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="genre" class="control-label col-lg-3">Genre</label>
                        <div class="col-lg-9">
                            <select id="genre" name="genre" class="form-control" required></select>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="nbr-pages" class="control-label col-lg-3">Number Pages</label>
                        <div class="col-lg-9">
                            <input type="number" id="nbr-pages" name="nbr-pages" class="form-control" required placeholder="Pages" />
                        </div>
                    </div>

                    <div id="tips">The objective of a synopsis or query letter is to entice enablers into requesting your manuscript. 
                                    It must be concise and to the point and of course very well written. One page is preferred and no more than 3 pages will be accepted.
                                    <a href="uploads/ron/3997524697.pdf" target="_blank">Sample Query Letter</a>                        
                    </div>
                    <p id="file-warning" class="thumbnail">Your synopsis/query letter must be a PDF file.
                        <a target="_blank" href="https://www.freepdfconvert.com/" target="_blank">Free file conversion to PDF.</a>
                    </p>
                    <div id="upload-container" tabindex="0">
                        <a id="file-upload" class="btn btn-custom-primary btn-file btn-block text-xs-center" role="button">Choose PDF to Upload
                            <br/><div id="filename" class="btn-block" style="color: #fff">No file chosen</div>
                        </a>
                        <input type="file" id="file2upload" style="display: none">
                    </div><br/>
                    <div class="form-group">
    <!--            <button type="submit" id="writers-submit" class="btn btn-custom-success btn-block m-t-8">Submit</button>-->
                    </div>
                    <div class="limited-offer">For a limited time, writer submissions will cost <span style="color: #f00; font-weight:bold">$20.00</span> to offset screening and editing costs and to promote quality synopsises and query letters. We reserve the right to change this policy without notice.</div>

    <!--                <form id="form-paypal" name="form-paypal" action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top" onsubmit="return ajaxSubmit()">-->
                    <input id="userid" name="userid" type="hidden" />
                    <input id="filesize-limit" name="filesize-limit" type="hidden" value="150000" /> 
                </form>
            </div> <!-- col-md-12 -->
            <div class="col-md-12">
                <form id="form-paypal" action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post" target="_top">
                    <input type="hidden" name="cmd" value="_s-xclick">
                    <input type="hidden" name="hosted_button_id" value="8MEQLAJ8WKG2L">
                    <input type="image" src="https://www.sandbox.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif" name="submit" alt="PayPal - The safer, easier way to pay online!">
                    <img alt="paypal" src="https://www.sandbox.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
                </form>
            </div> <!-- col-md-12 -->
        </div> <!-- row -->
    </div> <!-- container -->

答案 1 :(得分:1)

实际上,函数(== Nothing)作为类型(Eq a) => Maybe a -> Bool,在您的情况下,函数不是Eq类型类的成员,这不会编译。

但是,您可以使用isNothing中的Data.Maybe功能,或者您可以自己定义:{/ p>

isNothing :: Maybe a -> Bool
isNothing Nothing = True
isNothing (Just _) = False

由于您在构造函数上进行了模式匹配,因此未使用(==),因此您不需要a成为Eq的实例。

答案 2 :(得分:1)

这是因为您在比较表达式中使用Maybe (Integer -> Integer -> Integer)类型import qualified Data.Map as Map d = Map.fromList [('+', (+))] f :: Char -> Integer -> Integer -> Integer f key v1 v2 = case Map.lookup key d of Nothing -> 0 Just f -> f v1 v2 。 Haskell不知道如何比较两个函数。

解决方案是“解包”查找返回。

λ> f '-' 1 2                                                                                     
0                                                                                                
λ> f '+' 1 2                                                                                     
3                                                                                                
λ>  

import android.app.AlertDialog;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class Main2Activity extends AppCompatActivity {

    private static Button button_change;
    DatabaseClass myDb;
    EditText editText_name,editText_Quantity,editText_Category,editTextId,editText_Number;
    Button button_add;
    Button btnviewAll;
    Button btnviewUpdate;
    Button btnDelete;
    ListView lv;
    SearchView sv;
    ArrayAdapter<String> adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);


        myDb = new DatabaseClass(this);

        editText_name = (EditText) findViewById(R.id.editText_name);
        editText_Quantity = (EditText) findViewById(R.id.editText_Quantity);
        editText_Category = (EditText) findViewById(R.id.editText_Category);
        editText_Number = (EditText)findViewById(R.id.editText_Number);
        editTextId = (EditText) findViewById(R.id.editText_id);
        button_add = (Button) findViewById(R.id.button_add);
        btnviewAll = (Button) findViewById(R.id.view_all);
        btnviewUpdate = (Button) findViewById(R.id.button_update);
        btnDelete = (Button) findViewById(R.id.button_delete);


        AddData();
        viewAll();
        updateData();
        DeleteData();
        // OnClickButtonListener();


    }





    public void DeleteData(){
        btnDelete.setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Integer deletedRows = myDb.DeleteData(editTextId.getText().toString());
                        if(deletedRows > 0)
                            Toast.makeText(Main2Activity.this, "Data is Deleted", Toast.LENGTH_LONG).show();
                        else
                            Toast.makeText(Main2Activity.this, "Data is not Deleted", Toast.LENGTH_LONG).show();

                    }



                }

        );
    }
    public void updateData(){
        btnviewUpdate.setOnClickListener(
                new View.OnClickListener(){
                    @Override
                    public void onClick(View v){
                        boolean isUpdate = myDb.updateData(editTextId.getText().toString(), editText_name.getText().toString(),editText_Quantity.getText().toString(),
                                editText_Category.getText().toString(),editText_Number.getText().toString());
                        if ( isUpdate == true)
                            Toast.makeText(Main2Activity.this, "Data is Updated", Toast.LENGTH_LONG).show();
                        else
                            Toast.makeText(Main2Activity.this, "Data is not Updated", Toast.LENGTH_LONG).show();
                    }}
        );

    }
    public void AddData() {
        button_add.setOnClickListener(

                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                        if (editText_name.getText().toString().length() == 0)

                        {
                            Toast.makeText(getApplicationContext(), "Product Name cannot be Blank", Toast.LENGTH_LONG).show();
                            editText_name.setError("Product Name cannot be Blank");
                            return;
                        }
                            else if(editText_Quantity.getText().toString().length() == 0){

                            Toast.makeText(getApplicationContext(), "Quantity cannot be Blank", Toast.LENGTH_LONG).show();
                            editText_Quantity.setError("Quantity cannot be Blank");
                            return;

                        }

                        else if(editText_Category.getText().toString().length() == 0) {

                            Toast.makeText(getApplicationContext(), "ID cannot be Blank", Toast.LENGTH_LONG).show();
                            editText_Category.setError("ID cannot be Blank");
                            return;
                        }

                        else {
                            Toast.makeText(getApplicationContext(), "Validated Succesfully", Toast.LENGTH_LONG).show();
                        }

                        boolean isInserted = myDb.insertData(editText_name.getText().toString(),
                                editText_Quantity.getText().toString(),
                                editText_Category.getText().toString(),editText_Number.getText().toString());
                        if (isInserted = true)
                            Toast.makeText(Main2Activity.this, "Data is Inserted", Toast.LENGTH_LONG).show();
                        else
                            Toast.makeText(Main2Activity.this, "Data is not Inserted", Toast.LENGTH_LONG).show();



                        }
                    }

        );





    }

    public void viewAll(){
        btnviewAll.setOnClickListener(
                new View.OnClickListener()
                {
                    @Override
                    public void onClick(View v){
                        Cursor res = myDb.getAllData();
                        if(res.getCount()==0){
                            //show message
                            showMessage("Error","Nothing found");
                            return;
                        }
                        StringBuffer buffer = new StringBuffer();
                        while(res.moveToNext()){
                            buffer.append("Id:"+res.getString(0)+"\n");
                            buffer.append("Name:"+res.getString(1)+"\n");
                            buffer.append("Quantity:"+res.getString(2)+"\n");
                            buffer.append("Food Category:"+res.getString(3)+"\n");
                            buffer.append("Importance of Product:"+res.getString(4)+"\n");
                        }
                        //show all data
                        showMessage("Data",buffer.toString());
                    }
                }

        );
    }
    public void showMessage(String title,String Message){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setCancelable(true);
        builder.setTitle(title);
        builder.setMessage(Message);
        builder.show();

    }




    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        {
            switch (item.getItemId())
            {
                case R.id.action_settings : startActivity (new Intent(this, SecondActivity.class));
break;
                case R.id.catalogue :startActivity (new Intent(this, ScrollActivity.class));
                    break;

                case R.id.list :startActivity (new Intent(this, Product_List.class));
                    break;
            }
            return super.onOptionsItemSelected(item);
        }}
}