F#奇怪的模式匹配结果

时间:2015-10-06 14:02:48

标签: f#

我正在编写二进制搜索实现。我遇到的问题是模式匹配块。

使用模式匹配的代码返回奇怪的结果。第一个匹配块不会返回我期望的内容。它警告我(_,_)永远不会到达。

let binSearch (item:double) (arr:list<double>) =
    let rec binSearchRec first last =
        if first > last then
            let lastIndex = arr.Length-1
            let len = arr.Length
            match (first, last) with
            | (0, -1) -> System.String.Format("ITEM SMALLER THAN {0}", arr.[0])
            | (len, lastIndex) -> System.String.Format("ITEM BIGGER THAN {0}", arr.[lastIndex])
            | (_,_) -> System.String.Format("IN BETWEEN {0} AND {1}", arr.[last], arr.[first])
        else
            let mid = (first+last)/2
            match item.CompareTo(arr.[mid]) with
            | -1 -> binSearchRec first (mid-1)
            | 0 -> "CONTAINS"
            | 1 -> binSearchRec (mid+1) last
    binSearchRec 0 (arr.Length-1)

使用此if-else替代方案替换第一个match (first, last)调用效果很好:

if first = 0 && last = -1 then
    System.String.Format("ITEM SMALLER THAN {0}", arr.[0])
else if first = len && last = lastIndex then
    System.String.Format("ITEM BIGGER THAN {0}", arr.[lastIndex])
else
    System.String.Format("IN BETWEEN {0} AND {1}", arr.[last], arr.[first])

我不明白该匹配调用与if-else调用的不同之处以及为什么这种方法运行良好但模式匹配块没有。

一个奇怪的结果是(len, lastIndex)匹配中的打印len在匹配内返回错误的数字。对于长度为3的数组,匹配语句前的len打印将显示3,而匹配中的打印将显示为1.

1 个答案:

答案 0 :(得分:8)

匹配表达式中的一个分支是创建对现有符号的新绑定

public class MessageListenerTest {

@Autowired ApplicationContext context;

@Test
public void testEventListener() throws InterruptedException {
    SubscribableChannel eventsChannel = (SubscribableChannel) context.getBean("events");
    final CountDownLatch countDownLatch = new CountDownLatch(1);
    MessageHandler handler = new MessageHandler() {
        @Override
        public void handleMessage(Message<?> message) throws MessagingException {
            countDownLatch.countDown();
        } 
    };
    eventsChannel.subscribe(handler);
    String msg = "hello world!";
    JmsTemplate template = (JmsTemplate) context.getBean("jmsTemplate");
    template.convertAndSend("myQueue", msg);
    Assert.assertTrue(countDownLatch.await(2, TimeUnit.SECONDS));
}
}

所以这个分支与其他所有情况都匹配。

如果要匹配匹配表达式中的现有值,可以使用when clase:

| (len, lastIndex) -> ...

另一种选择是将 len lastIndex 声明为文字,以便在模式匹配中使用它们,但在您的情况下似乎并不自然。

| (a, b) when a = len && b = lastIndex -> ...